The from-source scanner bundle behind skillward — deterministic skill scanners in one offline, multi-arch image.
A multi-stage image builds skillward's scanner ensemble from version- and commit-pinned upstreams. The trivy vuln DB and semgrep ruleset are baked into the image, so every scan runs with the network severed. skillward orchestrates the container; this repo owns the detection payload and refresh policy.
- Requirements
- Image
- Tags
- Scanners
- Determinism
- Provenance
- Staying fresh
- Used by
- Security
- Contributing
- License
Docker, BuildKit, or any OCI runtime able to pull from the GitHub Container Registry (or the Docker Hub mirror).
ghcr.io/coroboros/skillward-bundle:{tag} — mirrored to docker.io/coroboros/skillward-bundle:{tag}, and in the GitLab Container Registry at registry.gitlab.com/coroboros/security/infrastructure/skillward-bundle:{tag}.
- Architectures:
linux/amd64,linux/arm64 - User: non-root
scanner(uid 10000) - Entrypoint: none — skillward invokes each scanner by name with its own argv. Consume the image through skillward.
| Tag | Runtime base | Architectures | Size | Source | Mutability |
|---|---|---|---|---|---|
<version> |
python:3.12-slim-bookworm |
amd64, arm64 |
820.3 MB (amd64), 780.5 MB (arm64) | SemVer git tag | immutable |
main |
same as <version> |
same as <version> |
varies by build | latest green main build |
rolling |
<sha> |
same as <version> |
same as <version> |
varies by build | every build | immutable |
Sizes are compressed layer sums from the GitLab Container Registry. The final runtime base source of truth is the FROM line in the Dockerfile. Pin the @sha256 digest downstream for byte-reproducible scans.
Built from version- and commit-pinned upstream sources (pins are ARGs in the Dockerfile, bumped by Renovate). Each adds a unique deterministic detection axis.
| Tool | License | Detection axis |
|---|---|---|
| SkillSpector | Apache-2.0 | Deepest SKILL.md taint → exec |
| cc-audit | MIT | Claude Skills / Hooks / MCP config audit |
| aguara | Apache-2.0 | Supply-chain across 9 ecosystems + agent content |
| cisco skill-scanner | Apache-2.0 | Multi-engine static — YAML, YARA, bytecode, pipeline taint |
| agent-audit | MIT | OWASP Agentic Top 10, tool-boundary taint |
| ramparts | Apache-2.0 | MCP servers + agent skills, static |
| semgrep | LGPL-2.1 | AST/dataflow with the OWASP-LLM ruleset |
| trivy | Apache-2.0 | SCA + misconfiguration + secrets |
| gitleaks | MIT | Secrets — regex + entropy |
Detection rules are never authored here — each tool brings its own. Package pins, reviewed rule commits, and offline data refreshes are owned here (see Staying fresh).
The image carries its detection rules and vulnerability data, so scans need no network and no API keys — skillward runs it with --network=none:
- trivy — the vuln DB is baked at
/opt/trivy-cache(--skip-db-update --offline-scan); misconfig runs on the checks bundle embedded in the trivy binary (--skip-check-update), refreshed with each trivy bump. - semgrep — the rule source is vendored at
/rules/llm-securityfrom a pinned commit; the registry is never contacted. - SkillSpector's OSV check and ramparts' optional LLM have no network or keys, so they fall back to static-only.
Every published image, via the shared coroboros/ci container-images template, is:
- multi-arch — BuildKit,
linux/amd64,linux/arm64; - gated — source secrets via
gitleaks, OS + language package CVEs via Trivy on the published:sha, and the offline scanner smoke before tag promotion; - signed — cosign keyless on the immutable digest, with a CycloneDX SBOM attestation.
On version tags, the promoted digest is published to the GitLab Registry, GitHub Container Registry, and Docker Hub. Each registry-local digest is signed and attested after copy.
A cosign signature is bound to the digest, not the tag — verify the pinned digest:
cosign verify \
--certificate-identity-regexp 'https://gitlab.com/coroboros/security/infrastructure/skillward-bundle//.*' \
--certificate-oidc-issuer https://gitlab.com \
ghcr.io/coroboros/skillward-bundle@sha256:<manifest-list-digest>Detection tracks upstream through Renovate and scheduled rebuilds:
- Renovate reads the
# renovate:pins in theDockerfileand opens a weekly bump merge request per tool — crates.io (cc-audit, ramparts), GitHub releases (aguara, gitleaks, trivy), PyPI (semgrep, cisco, agent-audit, PyJWT), and GitHub commits (semgrep rules). Patch/minor release bumps can automerge after the smoke and security gates; detection-content commit refs stay manual. - trivy's vuln DB is re-downloaded on every build; semgrep's rules stay on a reviewed commit SHA (Renovate proposes, a human merges).
- trivy is built from the pinned release tag while
TRIVY_CONTAINERD_VERSIONoverrides its containerd dependency until upstream ships a CVE-clean release binary. - SkillSpector has no release tag, so it stays a reviewed commit SHA. Renovate proposes; a human merges.
- A weekly pipeline schedule rebuilds even when no pin moved, so the trivy DB and Debian package fixes do not wait for a tool bump. Enable it once in Project → Build → Pipeline schedules (
0 6 * * 1onmain).
skillward pulls this image (skillward install) and runs each scanner inside it, fusing the findings into one verdict. The CLI references the signed digest and is versioned independently of the image.
Report a vulnerability privately via the security policy — ob@coroboros.com, never a public issue.
Bug reports and merge requests welcome.
- Open an issue before submitting non-trivial merge requests.
- Commits follow Conventional Commits.
- Sign off each commit (DCO):
git commit -s. - Target the
mainbranch. - A new scanner must run deterministically and offline, and add a detection axis the ensemble does not already cover.
- Add its build to the
Dockerfile, its check totest/smoke-test.sh, and its adapter in the skillward crate.
Build the image and run the smoke test locally:
docker build -t skillward-bundle:dev .
bash test/smoke-test.sh skillward-bundle:devThe smoke test runs each scanner offline against test/fixtures/malicious and fails if any finding-producing probe goes silent.