Skip to content

About

Supporting repository for GitRepositoryVulnerabilityScanner to allow for sharing actions with public repositories

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

7 Commits

Folders and files

Repository files navigation

Vulnerability scan actions

These GitHub Actions scan an Octopus repository for vulnerable dependencies and container packages. Each scan runs the tool, converts its output to normalized findings, and looks up each advisory in the GitHub Advisory Database. A CVE that the advisory database cannot score falls back to its CVE record at CVE.org. It pushes the result to the Octopus built-in feed. It does nothing else.

This repository is the scan half of the vulnerability remediation project. The reconcile half lives in OctopusDeploy/GitRepositoryVulnerabilityScanner, which is internal. The reconciler reads the findings from the feed. It creates, updates, and closes Linear tickets. The decisions behind the project live there too. ADR-009 explains why the scan half lives here in a public repository.

The two halves never call each other. The Octopus feed sits between them. They share the package naming convention in scan/common.sh and the package format in schemas/manifest.schema.json and schemas/findings.schema.json.

Use the actions

Adding a repository? Follow ONBOARDING.md in OctopusDeploy/GitRepositoryVulnerabilityScanner. That internal repository holds the one set of steps. The example workflows live in examples/workflows/ here.

The actions log in to Octopus with OIDC. They read the Octopus URL, space, and service account from scan/octopus.env. Your workflow passes none of them. The job needs permissions: id-token: write.

The scan never fails your build on findings. Today's pull request does not cause a new CVE. The job does fail when the scanner, an advisory lookup, the Octopus login, or the push fails. A failed job means no report reached Octopus.

What the job shows

The job log and the step summary show counts by severity only. They never show a package, a version, or an advisory. Many callers are public. Their logs are public too. The full findings go only to the Octopus feed. A notice or warning annotation on the run overview shows the same counts. The summary is for people only. The reconciler never reads it. A failed summary never fails the job.

Scan details

Each job produces three files:

  • findings.json: one entry for each vulnerability, with the package key, advisory, aliases, score, severity, and fixed versions. normalize/bin/normalize.js writes it. The schema is schemas/findings.schema.json.
  • <package-id>.json: the tool's own output, unchanged. It is evidence only.
  • manifest.json: what was scanned, with what, and from where. Its findings and report fields name the other two files. The schema is schemas/manifest.schema.json.

The job zips all three as vuln.<org>-<repo>.<scan>.<branch-slug> with version yyyy.M.d.HHmmss. It pushes the zip with scan/push-report.sh. The feed keeps the last 30 versions of each package.

  • dotnet: restores the solution, then runs dotnet list <sln> package --vulnerable --include-transitive --format json. With no project input it uses the single .sln in the repository root.
  • pnpm: runs pnpm audit --json --prod when the directory has pnpm-lock.yaml. It does not install packages.
  • npm: runs npm audit --json --omit=dev when the directory has package-lock.json.
  • go: runs govulncheck -format json ./... in the module directory. Install Go at the version in go.mod. govulncheck checks the standard library of the Go version that runs it. The action builds govulncheck in its own folder. It never changes your job's PATH or module cache. If your Go is newer than the pinned govulncheck supports, set govulncheck_version.
  • container: runs trivy image against the image the caller names.

The normalize step needs Node 18 or later. GitHub hosted runners have it. It reads GITHUB_TOKEN for advisory lookups. The actions pass the job token by default. A TeamCity build or a self-hosted runner must supply both. The runner also needs to reach cveawg.mitre.org. That API needs no key. An advisory or CVE record lookup that fails after retries fails the job. Nothing is pushed. The reconciler reports the missing package as a gap.

Change the schema

The reconciler keeps pinned copies of schemas/manifest.schema.json and schemas/findings.schema.json. Its CI fails when a copy drifts. Change a schema here first. Then update the copy in OctopusDeploy/GitRepositoryVulnerabilityScanner in a second pull request.

What lives here

scan/{dotnet,js,go,container}/  composite action and scanner script for each ecosystem
scan/octopus.env                 the Octopus URL, space, and service account every scan pushes to
scan/octopus.test.env            the Test instance. Only the canary uses it.
scan/load-octopus-env.sh         picks one of the two files. VULN_SCAN_TARGET=test picks the Test file.
normalize/                       converts a report to findings.json and looks up each advisory
scan/push-report.sh              zips the package and pushes it to the Octopus built-in feed
scan/common.sh                   naming convention, manifest writer
scan/summary.sh                  job summary with severity counts only
schemas/                         package manifest and findings contract
examples/workflows/              caller workflows to copy into a product repository
.github/workflows/ci.yml         shellcheck, actionlint, and normalize tests
.github/workflows/canary.yml     Test canary: scans test/canary/ daily with the actions at this commit
test/canary/                     projects with intentionally vulnerable packages. Never deployed.

The canary keeps a report for each scan in the Test environment. Its repository id is this repository. It sets VULN_SCAN_TARGET: test, so it keeps pushing to Test after scan/octopus.env moves to Production.

Run a scanner locally in three steps. Run these from a checkout of the repository you want to scan:

  1. bash scan/js/scan.sh ./out OctopusDeploy/<repo> main
  2. GITHUB_TOKEN=$(gh auth token) node normalize/bin/normalize.js ./out
  3. DRY_RUN=true bash scan/push-report.sh ./out

Run the normalize tests with npm test in normalize/.

Before first production use

  • Pin every third-party action in scan/, examples/workflows/, and .github/workflows/ to a commit SHA. Search for TODO pin. Pin trivy_version too.
  • Point scan/octopus.env at the production Octopus instance. Leave scan/octopus.test.env on Test. The canary uses it.

About

Supporting repository for GitRepositoryVulnerabilityScanner to allow for sharing actions with public repositories

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages