Skip to content

security: verify container release source and image attestations - #339

Open
m-khan-97 wants to merge 1 commit into
devfrom
fix/verified-container-release
Open

security: verify container release source and image attestations#339
m-khan-97 wants to merge 1 commit into
devfrom
fix/verified-container-release

Conversation

@m-khan-97

Copy link
Copy Markdown
Collaborator

Summary

I am taking the container release-integrity slice of #304. The existing Docker publisher runs independently of the signed source-release job, so a successful image publication does not establish the same source-verification guarantees.

This change removes the independent Docker tag/manual triggers and makes container publishing a dependent reusable workflow after the signed source release succeeds.

What is enforced

  • A GitHub-verified signed annotated stable vMAJOR.MINOR.PATCH tag must directly identify the event/checkout commit, and that commit must be on fetched main history.
  • The verified commit and tag-object identity pass between jobs. Tag identity and ancestry are rechecked before source publication, image publication and version promotion.
  • Build once, scan the saved image with the current Trivy policy, and generate the image SBOM from that same archive.
  • Push a unique candidate only after scanning. Bind provenance and CycloneDX SBOM attestations to its exact registry digest.
  • Verify both attestations against the repository, reusable signer workflow, source commit and tag before applying the release version tag. No rebuild during promotion and no moving latest/minor aliases.
  • Retain scan/SBOM/source/digest evidence. No new vulnerability exceptions or protection bypasses.

OWASP transition and explicit rollout control

GitHub now reports the canonical repository as OWASP/openshield. The proposed image destination is ghcr.io/owasp/openshield, replacing the historical namespace for future releases only. Nothing here migrates or deletes existing packages.

Container publication additionally requires the repository variable CONTAINER_RELEASE_ENABLED=true. Before enabling it, an OWASP administrator must confirm package creation/write permissions, visibility, tag authority and the first-release verification plan. I have not set that variable, changed settings, created a tag, dispatched a release or published an image.

The workflow must reach main before tagging a new release; historical tags retain their historical workflow code. A verified signature is not a separate trusted-signer allowlist, so branch/tag protections remain an administrative prerequisite under #298.

Validation

  • Full local suite on Python 3.11: 1,033 passed, 9 skipped; 86.50% API/scanner coverage. Skips: three BM25-index-dependent cases and six PostgreSQL-dependent cases.
  • 55 focused release tests: context/unsigned/moved/nested-tag rejection, malformed API responses, timeout/no-output behavior, real local Git ancestry, exact digest selection, mismatched digest rejection, workflow ordering and shell syntax.
  • Repository-wide ruff check and format check passed.
  • actionlint 1.7.12 passed on both changed workflows (shellcheck/pyflakes integrations disabled); shell blocks were separately parsed with bash -n in tests.
  • git diff --check passed.

Limits

No Docker daemon or live OIDC/registry publication was exercised locally. Tests validate the gate and workflow wiring, not a completed production release. The owner-approved first release must verify actual registry attestations and provide that operating evidence before announcement.

Registry push and signing are not atomic: a failed run may leave an unpromoted candidate. Source artifacts may already exist when the dependent container job fails. Consumers must verify and deploy the digest, never trust a candidate tag. Base/OS reproducibility, immutable version-tag enforcement, multi-architecture publishing and historical package migration are separate work.

Refs #304; deliberately leaves the broader issue open. Independent of #336.

Dependencies

Depends-On: none

…attestations

Signed-off-by: Muhammad Ibrahim <135441675+m-khan-97@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 1 package(s) with unknown licenses.
See the Details below.

License Issues

.github/workflows/docker.yml

PackageVersionLicenseIssue Type
aquasecurity/trivy-actioned142fd0673e97e23eac54620cfb913e5ce36c25NullUnknown License
Excluded from license check: pkg:pypi/azure-mgmt-containerservice@41.3.0, pkg:pypi/azure-mgmt-recoveryservices@4.1.0

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/attest-build-provenance 0f67c3f4856b2e3261c31976d6725780e5e4c373 UnknownUnknown
actions/actions/attest-sbom 4651f806c01d8637787e274ac3bdf724ef169f34 UnknownUnknown
actions/actions/upload-artifact ea165f8d65b6e75b540449e92b4886f43607fa02 🟢 5.2
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
License🟢 10license file detected
Fuzzing⚠️ 0project is not fuzzed
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
actions/aquasecurity/trivy-action ed142fd0673e97e23eac54620cfb913e5ce36c25 🟢 6.7
Details
CheckScoreReason
Code-Review🟢 9Found 15/16 approved changesets -- score normalized to 9
Maintained🟢 1014 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
Packaging⚠️ -1packaging workflow not detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 7detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
Security-Policy⚠️ 0security policy file not detected
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0

Scanned Files

  • .github/workflows/docker.yml

@m-khan-97

Copy link
Copy Markdown
Collaborator Author

Ritik and Parth, this is ready for review; please focus on the signed-tag/main-ancestry gate, the scanned-image-to-attested-digest path, and failure handling before version promotion. One coordination issue after the OWASP transfer: GitHub rejected my review request for @Vishnu2707 because it does not currently recognize him as a repository collaborator. An OWASP administrator should confirm his reviewer access or the intended replacement before we proceed through the normal approval process. I have not changed access or enabled container publication.

@TFT444 TFT444 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The release integrity chain is well constructed: container publishing is gated behind the signed source-release job, both provenance and SBOM attestations are produced and verified against the exact manifest digest before any version promotion, and release_integrity.py is exercised at each stage. Actions are pinned to SHAs. Approved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants