From e50105777f0b76ecc3342957d7f4432df9228c46 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 22:24:43 +0400 Subject: [PATCH 01/10] docs: add RELEASES.md covering release notes + vuln-disclosure flow Satisfies OpenSSF Best Practices bestpractices.dev criteria: - release_notes: documents that per-release human-readable notes live at https://github.com/simple-container-com/api/releases, auto-generated from PR titles (not raw git log) via gh release create --generate-notes in scripts/create-github-release.sh. - release_notes_vulns: documents the commit-subject convention (fix(security): / fix(deps): / hotfix:) that surfaces security changes in the release notes, plus how GitHub Security Advisories cross-link to the affected release. - report_archive: points at the public archive surfaces: - https://github.com/simple-container-com/api/issues - https://github.com/simple-container-com/api/pulls (closed) - https://github.com/simple-container-com/api/security/advisories Also covers: - 'How release notes are produced' (gh release create flow from push.yaml's docker-finalize job) - 'How to read a release for security implications' (per-tag step- by-step) - Release cadence (automatic prod on every merge to main; preview builds tagged but not turned into Releases; hotfixes use the same flow per PR #268 canonical example) - Cross-refs to SECURITY.md / CONTRIBUTING.md / MAINTAINERS.md / ARCHITECTURE.md / DEPENDENCIES.md / HARDENING.md so the doc reader can traverse the project documentation map. Signed-off-by: Dmitrii Creed --- docs/RELEASES.md | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 docs/RELEASES.md diff --git a/docs/RELEASES.md b/docs/RELEASES.md new file mode 100644 index 00000000..74f310fe --- /dev/null +++ b/docs/RELEASES.md @@ -0,0 +1,139 @@ +# Releases + +This doc covers how Simple Container (`sc`) is released, where to read +release notes, how vulnerabilities are surfaced in notes, and how the +release ↔ disclosure flow ties together. + +It satisfies the OpenSSF Best Practices `release_notes`, +`release_notes_vulns`, and `report_archive` criteria. + +## Where to read release notes + +| What | Where | +|---|---| +| **Per-release human-readable notes** | | +| **Public vulnerability advisories** | | +| **Public issue / PR archive (reports + responses)** | + | +| **Internal phase-by-phase hardening tracker** | [`HARDENING.md`](../HARDENING.md) (repo-side) | + +## How release notes are produced + +Every push to `main` triggers `.github/workflows/push.yaml`. After +build + sign + publish to dist, the `docker-finalize` job invokes +[`scripts/create-github-release.sh`](../scripts/create-github-release.sh) +which calls: + +```bash +gh release create "${VERSION}" "${assets[@]}" \ + --repo "${GITHUB_REPOSITORY}" \ + --title "v${VERSION}" \ + --generate-notes \ + --verify-tag +``` + +The `--generate-notes` flag uses GitHub's auto-generation: it walks +back to the previous tag and produces a categorised summary of merged +PRs since then, **plus** a "New Contributors" callout. This is **not** +raw `git log` output — it groups by PR + author + label, with PR +titles and authors hyperlinked. + +Release notes are attached to each Release object alongside the signed +sidecars (`.cosign-bundle`, `.sigstore.json`, `.sha256`, `.sbom.cdx.json`). +Consumers can verify the integrity of the artifacts AND read the notes +in the same Release UI. + +## How vulnerabilities appear in release notes + +Security-relevant changes follow these conventions so they surface +clearly in the auto-generated notes: + +1. **Commit subject prefix**: security fixes use `fix(security):` / + `fix(deps):` (for CVE-closing dep bumps) / `hotfix(...)`. Examples + from history: + + - `fix(deps): bump docs python 3.9 → 3.12-slim + pin requests/urllib3 to patched versions` + (closes GHSA-gc5v-m9x4-r6x2, GHSA-mf9v-mfxr-j63j, GHSA-qccp-gfcp-xxvc) + - `fix(deps): migrate aws-sdk-go v1 → v2 (Vulnerabilities 8→10)` + (addresses GO-2022-0635, GO-2022-0646) + - `hotfix(sc.sh): drop invalid --yes flag on cosign verify-blob` + (production outage — installs broken since #264) + +2. **CVE / GHSA references**: the body of every security-fix commit + includes the upstream advisory IDs (`GHSA-...`, `CVE-...`, + `GO-YYYY-NNNN`) it closes. These show up in the release-notes + summary via the linked PR. + +3. **GitHub Security Advisories**: when a security report reaches + maintainers via the channels in [`SECURITY.md`](SECURITY.md), the + fix lands via a regular PR, and the corresponding GHSA is published + on . + The advisory cross-links the affected version + the patch PR + the + release tag, so a consumer reading the release notes can pivot to + the advisory page directly. + +4. **N/A is honest**: if a given release fixed no publicly-known + vulnerabilities, no vulnerability section is forced into the notes. + The `--generate-notes` output simply omits a security callout. + +## Reading a release for security implications + +For a given release `vYYYY.M.X`: + +1. Open + (note: tag has no `v` prefix in our scheme; the Release title shows + `v` for human readability). +2. The auto-generated body lists every merged PR. Filter mentally for + PRs whose title starts with `fix(security)`, `fix(deps)`, or + `hotfix(...)`. +3. Click through to any PR for the full commit body — that's where the + CVE / GHSA ID lives. +4. Cross-check against the advisory archive at + + for any advisory marked **Published** with a `Patched in` field + matching this release. +5. The dist-side tarballs at `https://dist.simple-container.com/sc-*-vYYYY.M.X.tar.gz` + ship the same release. Verify their integrity with `cosign verify-blob` + per [`SECURITY.md`](SECURITY.md) before upgrading. + +## Release cadence + +- **Production releases**: cut automatically on every merge to `main`. + Calver scheme `YYYY.M.X` driven by + `reecetech/version-increment@2023.10.2`. There is no manual release + process — every accepted change in `main` ships. +- **Preview releases**: produced by `.github/workflows/branch-preview.yaml` + on a `workflow_dispatch` trigger from a feature branch. Tagged + `vYYYY.M.X-pre.SHORTSHA-preview.SHORTSHA`. These do NOT create GitHub + Release objects (filtered by `scripts/create-github-release.sh`), + but their signed sidecars are still published to `dist.*`. +- **Hotfixes**: same flow as a regular fix. Merge to `main` → + automatic release. No separate hotfix branch model. See PR #268 for + the canonical hotfix example (cosign `--yes` flag bug). + +## Vulnerability report archive + +Public issue and PR threads — including security-fix PR discussions +once their corresponding advisory is published — are archived at: + +- — open + closed + issues +- + — closed PRs +- — + Published GitHub Security Advisories + +GitHub's full-text search across these surfaces makes the archive +searchable without additional infrastructure. + +## Cross-references + +- [`SECURITY.md`](SECURITY.md) — threat model, reporting channels, + disclosure cadence +- [`CONTRIBUTING.md`](CONTRIBUTING.md) — contribution requirements +- [`MAINTAINERS.md`](MAINTAINERS.md) — who handles security responses +- [`ARCHITECTURE.md`](ARCHITECTURE.md) — system actors + trust + boundaries the release pipeline operates within +- [`DEPENDENCIES.md`](DEPENDENCIES.md) — dep selection + tracking that + drives most of the `fix(deps)` security PRs +- [`../HARDENING.md`](../HARDENING.md) — phase-by-phase hardening + tracker, including the deferred-CVE log From 8fb7f624c5c4751d454674447a379682fb1b1749 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 22:47:08 +0400 Subject: [PATCH 02/10] ci: blocking govulncheck workflow + OpenVEX for documented FPs (VM-04.02 + 05.03) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes OpenSSF Baseline OSPS-VM-05.03 ('changes MUST be automatically evaluated against documented policy for malicious deps and known vulnerabilities ... blocked in event of violations, except when declared and suppressed as non-exploitable') and OSPS-VM-04.02 ('vulnerabilities not affecting the project MUST be accounted for in a VEX document'). Adds: - .github/workflows/govulncheck.yml — runs govulncheck -mode=source on every PR + push to main + Monday cron. Reachability-aware: fails the build only if the vulnerability is actually reachable from our call graph. This filters out the aws-sdk-go v1 s3crypto false positives (GO-2022-0635, GO-2022-0646) without needing VEX consult because govulncheck knows we don't call NewDecryptionClient / NewEncryptionClient. SHA-pinned actions/checkout + actions/setup-go. Concurrency-keyed by commit SHA (same pattern as codeql.yml + fuzz.yml + dco.yml). - vex/openvex.json — formal OpenVEX v0.2.0 document declaring not_affected for GO-2022-0635 + GO-2022-0646. justification: vulnerable_code_not_in_execute_path. impact_statement cites govulncheck output as evidence. Consumed by VEX-aware tools (Trivy --vex, Grype --vex) so they suppress correctly too. This is the enforcement half of the SCA policy documented in docs/DEPENDENCIES.md (next commit). Suppressions ONLY via VEX — no .trivyignore, no # nosemgrep, no // nolint per project policy in CONTRIBUTING.md. Empirically verified: govulncheck -mode=source ./... currently reports 'Your code is affected by 0 vulnerabilities.' so this gate does NOT regress today's posture; it just enforces it going forward. Signed-off-by: Dmitrii Creed --- .github/workflows/govulncheck.yml | 76 +++++++++++++++++++++++++++++++ vex/openvex.json | 48 +++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 .github/workflows/govulncheck.yml create mode 100644 vex/openvex.json diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml new file mode 100644 index 00000000..6571f5ad --- /dev/null +++ b/.github/workflows/govulncheck.yml @@ -0,0 +1,76 @@ +name: govulncheck + +# Reachability-aware vulnerability scan against every PR + push to main. +# Fails the build if our code calls into a known-vulnerable function in +# any direct or transitive Go dep. +# +# This is the enforcement half of the documented SCA policy in +# docs/DEPENDENCIES.md "Pre-release SCA gate". OpenSSF Baseline +# OSPS-VM-05.03 requires changes to be automatically evaluated against +# a documented policy and blocked on violation, except when declared +# non-exploitable (which we do via vex/openvex.json). +# +# Why govulncheck instead of osv-scanner / Trivy on Go modules: +# govulncheck is the reachability-aware scanner maintained by the Go +# security team. It runs the call-graph against the OSV advisory data +# and reports only vulnerabilities whose symbols are reachable from +# OUR code. Module-level scanners (osv-scanner, Trivy) flag any vuln +# in any transitive dep regardless of whether the vulnerable symbol +# is called — which produces false positives like GO-2022-0635/0646 +# (aws-sdk-go v1 s3crypto, transitively pulled in by Pulumi but never +# called). Those false positives are documented in vex/openvex.json +# but govulncheck filters them at the scan level without needing the +# VEX consult. +# +# CI behaviour: +# - PR: fails if govulncheck reports any reachable vulnerability. +# - main push: same gate; an unfixable transitive that suddenly +# becomes reachable would block the next release. +# - Weekly cron: catches newly-published advisories landing against +# existing reachable code paths. + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '37 6 * * 1' # Monday 06:37 UTC — early week, off-peak + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.head.sha || github.sha }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + govulncheck: + name: govulncheck (reachability-aware) + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + with: + go-version-file: go.mod + cache: true + + - name: Install govulncheck + run: | + set -euo pipefail + go install golang.org/x/vuln/cmd/govulncheck@latest + govulncheck -version + + - name: Run govulncheck on source + run: | + set -euo pipefail + # -mode=source: scan the call graph from this module's main + # packages outward (reachability-aware). Exits non-zero if + # any reachable vulnerability is found. + govulncheck -mode=source ./... diff --git a/vex/openvex.json b/vex/openvex.json new file mode 100644 index 00000000..8f59a3a8 --- /dev/null +++ b/vex/openvex.json @@ -0,0 +1,48 @@ +{ + "@context": "https://openvex.dev/ns/v0.2.0", + "@id": "https://simple-container.com/.well-known/openvex/api.json", + "author": "Simple Container maintainers ", + "timestamp": "2026-05-18T19:00:00Z", + "version": 1, + "tooling": "Hand-authored. Reachability evidence from `govulncheck -mode=source ./...`.", + "statements": [ + { + "vulnerability": { + "@id": "https://pkg.go.dev/vuln/GO-2022-0635", + "name": "GO-2022-0635", + "aliases": ["CVE-2020-8911"], + "description": "In-band key negotiation issue in AWS S3 Crypto SDK for golang. Affected symbols: github.com/aws/aws-sdk-go/service/s3/s3crypto NewDecryptionClient, NewEncryptionClient." + }, + "products": [ + { + "@id": "pkg:golang/github.com/simple-container-com/api", + "subcomponents": [ + { "@id": "pkg:golang/github.com/aws/aws-sdk-go" } + ] + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_in_execute_path", + "impact_statement": "github.com/aws/aws-sdk-go is required transitively by github.com/pulumi/pulumi/pkg/v3/operations. Neither this codebase nor Pulumi's operations package imports github.com/aws/aws-sdk-go/service/s3/s3crypto. govulncheck -mode=source ./... reports 0 reachable vulnerabilities (and explicitly identifies these two advisories as 'vulnerabilities in modules you require, but your code doesn't appear to call these vulnerabilities')." + }, + { + "vulnerability": { + "@id": "https://pkg.go.dev/vuln/GO-2022-0646", + "name": "GO-2022-0646", + "aliases": ["CVE-2020-8912"], + "description": "CBC padding oracle issue in AWS S3 Crypto SDK for golang. Affected symbols: github.com/aws/aws-sdk-go/service/s3/s3crypto NewDecryptionClient, NewEncryptionClient." + }, + "products": [ + { + "@id": "pkg:golang/github.com/simple-container-com/api", + "subcomponents": [ + { "@id": "pkg:golang/github.com/aws/aws-sdk-go" } + ] + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_in_execute_path", + "impact_statement": "Same as GO-2022-0635 — s3crypto subpackage is not imported by this codebase or by any code path Pulumi's operations package reaches. govulncheck reachability scan confirms zero reachable calls to the affected symbols." + } + ] +} From 82e01bd055a6c83b4af9837b20a220c5550303f4 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 22:47:08 +0400 Subject: [PATCH 03/10] docs(deps): add SCA remediation policy + pre-release gate (VM-05.01 + 05.02 + 05.03) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Appends two new sections to docs/DEPENDENCIES.md: 'Remediation thresholds (SCA policy)' — closes OSPS-VM-05.01 ('the project documentation MUST include a policy that defines a threshold for remediation of SCA findings related to vulnerabilities and licenses'): - Severity table: CRITICAL 24h/7d, HIGH 30d, MEDIUM 90d, LOW next-pass. SLA clock starts when govulncheck confirms reachability. - License-allow table: MIT/Apache-2.0/BSD-3/BSD-2/ISC/MPL-2.0 ✅; LGPL ⚠️ case-by-case; GPL/AGPL ❌ for runtime; unknown ❌. 'Pre-release SCA gate' — closes OSPS-VM-05.02 ('policy to address SCA violations prior to any release') and the documentation half of OSPS-VM-05.03. Production releases are cut automatically on every merge to main, so 'pre-release' = 'pre-merge'. The gate runs on every PR + push: - govulncheck (.github/workflows/govulncheck.yml, previous commit) — blocks on reachable Go advisories - CodeQL — blocks on ERROR-severity findings - Semgrep — blocks on ERROR-severity findings - TruffleHog — blocks on verified secrets - Dependabot — visibility (auto-PRs become blocking items via the SLA) - Trivy/Grype — reports counts; will graduate to blocking on HIGH/CRITICAL once VEX consumption wires in across the shared security-scan workflow 'Suppressing a finding (non-exploitable / false positive)' — closes the suppression half of OSPS-VM-05.03. Only sanctioned channel is VEX (vex/openvex.json). .trivyignore / # nosemgrep / // nolint / # noqa are NOT sanctioned suppression channels. Suppression flow is itself documented policy: reachable findings without a VEX not_affected entry block the merge. Signed-off-by: Dmitrii Creed --- docs/DEPENDENCIES.md | 78 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/docs/DEPENDENCIES.md b/docs/DEPENDENCIES.md index b205aace..17b5f281 100644 --- a/docs/DEPENDENCIES.md +++ b/docs/DEPENDENCIES.md @@ -106,3 +106,81 @@ These are not "deps" in the tree-sense, but the trust chain matters the same way: each ships with cosign keyless signature + SLSA L3 provenance + SHA256. Consumers verify via the patterns documented in [SECURITY.md](SECURITY.md). + +## Remediation thresholds (SCA policy) + +This section satisfies OpenSSF Baseline **OSPS-VM-05.01** +("the project documentation MUST include a policy that defines a +threshold for remediation of SCA findings related to vulnerabilities +and licenses") and is the contract the pre-release gate enforces. + +### Vulnerability severity → remediation SLA + +| Severity (CVSS or distro rating) | Remediation SLA | Behaviour while open | +|---|---|---| +| **CRITICAL** (9.0–10.0) | within **24 hours** of confirmation if there is a known patched version; within **7 days** if upstream fix pending | merge gate blocks all non-emergency PRs | +| **HIGH** (7.0–8.9) | within **30 days** | merge gate blocks; documented exceptions require VEX (see below) | +| **MEDIUM** (4.0–6.9) | within **90 days** | best-effort with batch bumps via Dependabot | +| **LOW** (0.1–3.9) | next scheduled SCA pass (~weekly) | informational | + +The SLA clock starts when the advisory is confirmed reachable in our +codebase by `govulncheck` (reachability-aware). If govulncheck reports +an advisory as *not* reachable, the finding does NOT block — it is +declared `not_affected` via `vex/openvex.json` with the govulncheck +output as evidence (per OSPS-VM-04.02). + +### License policy + +| License class | Allowed for direct + transitive deps | +|---|---| +| MIT / Apache-2.0 / BSD-3-Clause / BSD-2-Clause / ISC / MPL-2.0 | ✅ Allowed | +| LGPL (any version) | ⚠️ Flagged for maintainer review; case-by-case | +| GPL / AGPL (any version) | ❌ Rejected for runtime; allowed for build-only tooling iff the tool is not redistributed | +| Unknown / proprietary | ❌ Rejected | + +License compliance is checked at PR review time. License-incompatible +deps are blocked at merge by maintainer review (no automated license +scanner yet — tracked in HARDENING.md). + +## Pre-release SCA gate + +This section satisfies OpenSSF Baseline **OSPS-VM-05.02** ("a policy +to address SCA violations prior to any release") and **OSPS-VM-05.03** +("automatically evaluated against a documented policy ... then blocked +in the event of violations"). + +Production releases are cut automatically on every merge to `main` +(`.github/workflows/push.yaml`), so "pre-release" semantically equals +"pre-merge" — every release IS a merge to main. The SCA gate fires +on every PR + every push to main: + +| Tool | Coverage | Blocks on | +|---|---|---| +| **govulncheck** (`.github/workflows/govulncheck.yml`) | Reachable Go vulnerabilities (call-graph aware) | Any reachable advisory finding | +| **CodeQL** (`.github/workflows/codeql.yml`) | Common-vulnerability patterns (SQL injection, XSS, command injection, taint flow, SSRF) | ERROR-severity findings | +| **Semgrep** (`.github/workflows/semgrep.yml`) | Custom rules from the SC org (sigstore, gha-extras, pulumi-iac, go-canon) | ERROR-severity findings | +| **TruffleHog** (`.github/workflows/security-scan.yml`) | Leaked secrets in diff | Any verified secret | +| **Dependabot** | Daily advisory poll → auto-PR for known vulns | Open security alert (visibility, not blocking, but the auto-PR becomes a blocking item per the SLA above) | +| **Trivy / Grype** (in shared security-scan workflow) | SBOM-based scan of source-tree deps | Currently reports counts only; planned to graduate to blocking on HIGH/CRITICAL once VEX consumption is wired in | + +### Suppressing a finding (non-exploitable / false positive) + +The only sanctioned suppression channel is **VEX**: edit +`vex/openvex.json` and add a `not_affected` statement with: + +- `vulnerability.@id` — the OSV / CVE / GHSA ID +- `justification` — one of the OpenVEX standard values + (`vulnerable_code_not_in_execute_path`, + `inline_mitigations_already_exist`, etc.) +- `impact_statement` — free-form explanation citing evidence + (e.g., govulncheck output, code-path analysis, mitigation in place) + +`.trivyignore`, `# nosemgrep`, `// nolint:`, `# noqa` are NOT +sanctioned suppression channels. Any of these in a PR must point at +a documented false positive in the PR description; the project +prefers the formal VEX statement for tracking. + +Per OSPS-VM-05.03, the suppression flow is also "documented policy": +findings reachable in our code WITHOUT a VEX `not_affected` entry +block the merge. Findings declared `not_affected` in VEX bypass the +gate. From f1f8b5a9a33b85a1625520fa5100b9a3a198da16 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 22:47:09 +0400 Subject: [PATCH 04/10] docs: add SECRETS-POLICY.md for secret + credential management (BR-07.02) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes OpenSSF Baseline OSPS-BR-07.02 — 'the project MUST define a policy for managing secrets and credentials used by the project. The policy should include guidelines for storing, accessing, and rotating secrets and credentials.' Covers: - Categories of secret (CI/CD vs prod runtime vs maintainer-personal vs Sigstore signing identity vs test fixtures) - Storing rules: no commit (TruffleHog + GitHub secret-scanning push- protection enforced), encrypted-at-rest only, no SOPS-in-repo, fixture placeholder requirements - Accessing rules: least-privilege per CI job (Scorecard Token-Permissions=10), no pull_request_target on untrusted-PR workflows, no secret values in logs, step-scoped env - Rotation cadence: CI publish tokens 90d, Cloudflare quarterly, GitHub PATs 90d, Sigstore Fulcio per-build, prod runtime per consumer policy - On-leak procedure: rotate immediately → audit platform logs → GHSA if affects published artifacts → document in post-mortem - Detection: TruffleHog + GitHub secret-scanning + Semgrep custom rules - Cross-references to SECURITY.md / MAINTAINERS.md / DEPENDENCIES.md / HARDENING.md Per-maintainer specific ACL membership intentionally not published here (kept in private SC team credential inventory) to avoid leaking attack surface, matching MAINTAINERS.md threat-model approach. Signed-off-by: Dmitrii Creed --- docs/SECRETS-POLICY.md | 99 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 docs/SECRETS-POLICY.md diff --git a/docs/SECRETS-POLICY.md b/docs/SECRETS-POLICY.md new file mode 100644 index 00000000..8624e8b3 --- /dev/null +++ b/docs/SECRETS-POLICY.md @@ -0,0 +1,99 @@ +# Secrets & Credentials Policy + +This document satisfies OpenSSF Baseline **OSPS-BR-07.02** — +"the project MUST define a policy for managing secrets and credentials +used by the project. The policy should include guidelines for storing, +accessing, and rotating secrets and credentials." + +It complements [`SECURITY.md`](SECURITY.md) (threat model + disclosure) +and [`MAINTAINERS.md`](MAINTAINERS.md) (who holds what). + +## Categories of secret + +| Category | Examples | Where they live | +|---|---|---| +| **CI/CD secrets** | `SC_CONFIG` SC stack configuration, Docker Hub publish token, Telegram CI bot token | GitHub Actions encrypted secrets, repo-scoped | +| **Production runtime secrets** | DB credentials, Pulumi state encryption keys, customer-supplied cloud credentials | Consumer-side AWS Secrets Manager / GCP Secret Manager (NEVER in this repo) | +| **External-platform admin tokens** | Cloudflare API tokens, NameCheap API access, GitHub PATs for cross-repo access | Maintainer-personal vaults (1Password, similar); never committed | +| **Sigstore signing identity** | The build workflow's GitHub OIDC token used by cosign keyless sign | Ephemeral; minted per-build by GitHub Actions, valid ~10 min | +| **Test fixtures with placeholder credentials** | Example secrets YAML in `docs/docs/examples/secrets/`, `pkg/api/secrets/testdata/` | Repo, but in a format that TruffleHog excludes (per `.github/workflows/security-scan.yml` `secret-scan-extra-excludes`) | + +## Storing secrets + +- **Never commit** real secrets to the repo. TruffleHog runs on every + PR diff in `.github/workflows/security-scan.yml` and fails the build + on detected findings (`fail-on-secrets: true`). GitHub + secret-scanning push-protection is also enabled at the repo level. +- **Encrypted-at-rest only**: CI secrets in GitHub Actions; production + secrets in AWS Secrets Manager or GCP Secret Manager (consumer side). +- **No plain-text checked-in encrypted secrets**: even SOPS/Mozilla + encrypted-blobs in the repo are discouraged. Use the platform's + native secret store. +- **Example / test fixtures** must use clearly-non-credential + placeholders (``, `xxxxxxxxxxxxxxx`). Where the + fixture's format requires a real-shaped string (e.g., OpenSSH key + body in `pkg/api/secrets/testdata/`), the file is excluded via the + central TruffleHog excludes list in the shared security-scan + workflow. + +## Accessing secrets + +- **Principle of least privilege per CI job**: workflows set root + `permissions:` to `contents: read`; per-job `write` only where + required (e.g., `docker-finalize` for tag push + Release create). + Scorecard Token-Permissions = 10/10 after PR #263 enforces this. +- **No `pull_request_target`** on workflows that handle untrusted PR + code. The shared security scan uses `pull_request` so fork PRs run + with a read-only token and no access to org secrets. +- **No secrets in workflow logs**: GitHub Actions auto-redacts known + secret values; we add no debug echoes of env vars that might + contain secrets. +- **Job-scoped env**: secrets passed to steps via `env:` at the step + level (or `env:` on the smallest enclosing job), never globally. + +## Rotation cadence + +| Secret type | Cadence | Trigger | +|---|---|---| +| **CI publish tokens** (Docker Hub, Sigstore-key alternatives if any) | 90 days | Calendar reminder; immediate on suspected leak | +| **Cloudflare API tokens** (Maintainer-personal) | Quarterly | Calendar; immediate on maintainer offboarding | +| **GitHub Personal Access Tokens** (for cross-repo automation) | 90 days, scoped to specific repos only | Calendar | +| **Sigstore Fulcio certs** (per-build) | Per-build (~10 min lifetime) | Automatic | +| **Production runtime secrets** (DB creds, etc.) | Per consumer's policy | Owned by consumer | + +Rotation is recorded in the maintainer's credential inventory (kept +in a private SC team vault, not published here per +[`MAINTAINERS.md`](MAINTAINERS.md) "Sensitive-resource access map"). + +## On suspected leak + +1. **Rotate immediately** — don't wait for the next scheduled cadence. +2. **Audit the access logs** of the platform the secret was on + (GitHub Audit Log, Cloudflare Audit Log, Docker Hub access log, + AWS CloudTrail, etc.). Cloudflare audit-log retention is currently + 18 months on the SC `simple-container.com` account (Free-tier + default, satisfies OpenSSF ≥1-year requirement). +3. **Open a private security advisory** via the channel in + [`SECURITY.md`](SECURITY.md) if the leak affects a published artifact. +4. **Document the incident** in the post-mortem PR description (no + secret values, just the rotation reference + access-log summary). + +## Detection + +- **TruffleHog** on every PR diff (`.github/workflows/security-scan.yml` + via the shared `simple-container-com/actions/.github/workflows/security-scan.yml`). +- **GitHub secret-scanning** with **push-protection**: blocks pushes + that contain recognised credential formats. +- **Semgrep** custom rules (`simple-container-com/actions/semgrep-scan`) + flag patterns like hardcoded JWTs, AWS access keys in code, + embedded private keys. + +## Cross-references + +- [`SECURITY.md`](SECURITY.md) — threat model + disclosure +- [`MAINTAINERS.md`](MAINTAINERS.md) — who holds maintainer-personal + credentials +- [`DEPENDENCIES.md`](DEPENDENCIES.md) — dep policy +- [`../HARDENING.md`](../HARDENING.md) — Phase 6 admin-UI checklist + including Docker Hub 2FA + Cloudflare API-token audit + GCS service- + account key audit From 1f4f38719872333b21ce25e5938817b29acca0cd Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 22:47:09 +0400 Subject: [PATCH 05/10] docs(security): explicit support scope + EOL policy (DO-04.01 + DO-05.01) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes OpenSSF Baseline OSPS-DO-04.01 ('descriptive statement about the scope and duration of support for each release') and OSPS-DO-05.01 ('descriptive statement when releases or versions will no longer receive security updates'). The previous 'Supported versions' section was vague ('most recent calver release supported, older versions receive no patches'). Tightens this to two named subsections matching the Baseline criteria labels: Support scope (OSPS-DO-04.01): - Continuous-calver model — production release cut on every merge to main; supported version moves continuously. No LTS branch. - Latest vYYYY.M.x: ✅ active support - Previous vYYYY.M.x same month line: ✅ best-effort HIGH/CRIT back- port per DEPENDENCIES.md SLA - Older: ❌ no patches End-of-life policy (OSPS-DO-05.01): - A release is EOL the moment the next vYYYY.M.x ships - No security updates to older releases (including HIGH/CRIT) - Supported upgrade path = bump to latest - Consumers should pin to a tag and update at least monthly - Rationale spelled out: fewer than 5 active maintainers; LTS would dilute attention on the active head; calver + reproducible verified artifacts is the supported posture - Exception process for regulatory/contractual constraints — case- by-case, not part of the public policy Signed-off-by: Dmitrii Creed --- docs/SECURITY.md | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/docs/SECURITY.md b/docs/SECURITY.md index ce023c88..eeb121fb 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -7,19 +7,40 @@ all reports as high priority. ## Supported versions -Security fixes are issued for the **most recent calver release** (the -tag pushed by [`.github/workflows/push.yaml`][push] on every merge to -`main`) and back-ported to the latest `vYYYY.M.x` line only when the -fix is non-trivial. Older versions receive no patches; consumers should -pin to a recent release tag (or a SHA) and update via Dependabot / -[`integrail/devops/.github/actions/install-sc`][install-sc] (or -equivalent) on at least a monthly cadence. - -| Version | Supported | +### Support scope (OSPS-DO-04.01) + +`sc` ships **production calver releases on every merge to `main`** via +[`.github/workflows/push.yaml`][push]. Each release is supported for +security fixes **until the next calver release ships**. There is no +LTS branch model; the supported version moves continuously. + +| Version | Supported for security fixes | |---|---| -| `vYYYY.M.x` latest | ✅ | -| Previous calver release on the same month line | ✅ (best-effort back-port) | -| Anything older | ❌ | +| Latest `vYYYY.M.x` published at | ✅ Active support | +| Previous `vYYYY.M.x` on the same month line | ✅ Best-effort back-port for HIGH/CRIT only; SLA per [`DEPENDENCIES.md`](DEPENDENCIES.md) "Remediation thresholds" | +| Older releases | ❌ No patches; see EOL policy below | + +### End-of-life policy (OSPS-DO-05.01) + +A release becomes **EOL the moment a newer `vYYYY.M.x` ships**. The +practical implication is: + +- Older releases receive **no security updates** going forward — + including HIGH/CRITICAL fixes. +- The only supported upgrade path is to the latest calver release. +- Consumers MUST pin to a specific release tag (or a SHA) and update + at least monthly via Dependabot or the equivalent in + [`integrail/devops/.github/actions/install-sc`][install-sc]. +- This policy is intentional: SC has fewer than five active + maintainers, and an LTS branch model would dilute attention on the + active head. Continuous-release calver with reproducible verified + artifacts (Phase 2 cosign + SLSA L3) is the supported posture. + +If a consumer has a regulatory or contractual constraint that +prevents a monthly update cadence, contact the maintainers via the +channels in this document before pinning to an older release; we may +be able to coordinate a privately-supported branch on a case-by-case +basis (not covered by this public policy). ## Reporting a vulnerability From d94b17bad532c84d06e6e482c9e1f1deb2714d09 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 22:47:09 +0400 Subject: [PATCH 06/10] docs(maintainers): add collaborator-review policy for escalated permissions (GV-04.01) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes OpenSSF Baseline OSPS-GV-04.01 — 'the project documentation MUST have a policy that code collaborators are reviewed prior to granting escalated permissions to sensitive resources.' Adds 'Promoting a contributor / Granting escalated permissions' section to MAINTAINERS.md with five named gates: 1. Track-record gate: 5+ merged PRs over >=3 months, demonstrated review-and-iterate behaviour, no suppression-policy violations. 2. Sponsorship gate: existing maintainer nomination + second from another maintainer (or project lead if only one) + contributor acceptance. 3. Account-hardening gate: 2FA verified on GitHub / Docker Hub / Cloudflare BEFORE any resource ACL change; SSH/GPG signing key registered + matches identity. 4. Least-privilege grant: only the credentials needed for declared work scope; per-credential ACL recorded in private inventory. 5. Probationary period: first 30 days co-reviewed by an existing maintainer. Also expands 'Adding or removing a maintainer (mechanics)' offboarding flow to cross-link SECRETS-POLICY.md rotation schedule (accelerated to immediate on offboard). Signed-off-by: Dmitrii Creed --- docs/MAINTAINERS.md | 71 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/docs/MAINTAINERS.md b/docs/MAINTAINERS.md index 66fe6951..19265612 100644 --- a/docs/MAINTAINERS.md +++ b/docs/MAINTAINERS.md @@ -92,7 +92,69 @@ per-maintainer ACL membership is tracked in the SC team's internal credential inventory (not published here to avoid leaking attack surface, but maintained per `SECURITY.md`'s threat model). -## Adding or removing a maintainer +## Promoting a contributor / Granting escalated permissions + +This section satisfies OpenSSF Baseline **OSPS-GV-04.01** — +"the project documentation MUST have a policy that code collaborators +are reviewed prior to granting escalated permissions to sensitive +resources." + +A contributor is considered for maintainer-role promotion only after +the following review-and-vetting gates are passed. Each gate is +recorded in the promotion PR description. + +### Track-record gate + +- **Minimum**: 5+ merged PRs over ≥3 months, spanning multiple files + / packages. +- Demonstrated review-and-iterate behaviour (responsive to reviewer + feedback, clean commit history, signed commits with DCO sign-off). +- No suppression-policy violations in merged PRs (`.trivyignore`, + `# nosemgrep`, `// nolint:` etc. used outside the sanctioned VEX + channel documented in [DEPENDENCIES.md](DEPENDENCIES.md)). + +### Sponsorship gate + +- An existing maintainer must **explicitly nominate** the contributor + in a PR amending this file, with rationale. +- A second maintainer (or, if only one maintainer exists, the project + lead) seconds the nomination. +- The contributor accepts in the PR thread. + +### Account-hardening gate (must pass BEFORE any resource ACL changes) + +The promoting maintainer verifies and records (in the promotion PR +description) that the candidate's accounts meet: + +- ✅ **2FA enabled** on GitHub (TOTP or hardware key — NOT SMS). +- ✅ **2FA enabled** on Docker Hub if they will receive `simplecontainer` + org access. +- ✅ **2FA enabled** on Cloudflare if they will receive zone admin. +- ✅ **SSH/GPG commit-signing key** is registered in GitHub and matches + the GitHub account identity (no impersonation surface). Signed + commits will be required on every PR they merge. + +### Least-privilege grant + +- Even after promotion, the new maintainer receives **only the + credentials needed for their work**. Per the SECURITY.md threat + model, not every maintainer holds every key. +- Specifically: Docker Hub publish access is granted only if the + maintainer regularly handles releases; Cloudflare admin only if + they own DNS/WAF; AWS Secrets Manager only if they own the + infrastructure that consumes those secrets. +- Specific per-credential ACL membership is recorded in the SC team's + internal credential inventory (not in this public file) per + [SECRETS-POLICY.md](SECRETS-POLICY.md). + +### Probationary period + +- For the first 30 days after promotion, the new maintainer's merges + are **co-reviewed** by an existing maintainer — they may approve, + but another maintainer must also approve before merge. After 30 + days with no concerns, full merge authority becomes effective. + +## Adding or removing a maintainer (mechanics) Changes to this list happen via a PR amending this file + a corresponding update to: @@ -106,11 +168,12 @@ Maintainer offboarding additionally: - Rotates any shared CI tokens / API keys the departing maintainer could access (Docker Hub publish token, Cloudflare API tokens, - GitHub PAT-equivalents) + GitHub PAT-equivalents) — per [SECRETS-POLICY.md](SECRETS-POLICY.md) + rotation schedule, accelerated to "immediate" on offboarding. - Revokes Sigstore / cosign signing identities if the maintainer's - GitHub workflow identity was wired into any signing path + GitHub workflow identity was wired into any signing path. - Audits org-level 2FA enforcement (per - [HARDENING.md](../HARDENING.md) Phase 8 admin-UI list) + [HARDENING.md](../HARDENING.md) Phase 8 admin-UI list). ## Security contact From fe4c95b9b79d3e02f6b36d21667018aeca635675 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 23:10:46 +0400 Subject: [PATCH 07/10] docs(readme): add OpenSSF Best Practices badge (project 12886) Surfaces the bestpractices.dev Passing/Silver/Gold tier badge alongside the existing OpenSSF Baseline badge. Both link to the same project page; the Best Practices badge tracks the tier we earn from the self-attestation answers (which this PR's docs additions are meant to make Met-able). Signed-off-by: Dmitrii Creed --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9885a7a2..ad9308e0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # **Simple Container** [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/simple-container-com/api/badge)](https://scorecard.dev/viewer/?uri=github.com/simple-container-com/api) +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12886/badge)](https://www.bestpractices.dev/projects/12886) [![OpenSSF Baseline](https://www.bestpractices.dev/projects/12886/baseline)](https://www.bestpractices.dev/projects/12886) [![CodeQL](https://github.com/simple-container-com/api/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/simple-container-com/api/actions/workflows/codeql.yml) [![Semgrep](https://github.com/simple-container-com/api/actions/workflows/semgrep.yml/badge.svg?branch=main)](https://github.com/simple-container-com/api/actions/workflows/semgrep.yml) From e8d601d391db3b8bb57e6777c815907335fa2157 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 23:35:37 +0400 Subject: [PATCH 08/10] docs: add CODE_OF_CONDUCT and ROADMAP, link from README Closes the OpenSSF Best Practices code_of_conduct and documentation_roadmap criteria, surfaces both from the README so contributors land on them via the standard GitHub repo header. - docs/CODE_OF_CONDUCT.md: Contributor Covenant 2.1 verbatim with the reporting contact wired to creed@simple-container.com (consistent with docs/SECURITY.md + docs/MAINTAINERS.md security contacts). - docs/ROADMAP.md: rolling-release cadence note, Issues-label-driven state, current themes, "how a roadmap item becomes shipped code" flow pointing at CONTRIBUTING.md and MAINTAINERS.md. - README.md: extends the Contributing section to mention the CoC and adds a Roadmap section above License. Signed-off-by: Dmitrii Creed --- README.md | 8 +++- docs/CODE_OF_CONDUCT.md | 87 +++++++++++++++++++++++++++++++++++++++++ docs/ROADMAP.md | 71 +++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 docs/CODE_OF_CONDUCT.md create mode 100644 docs/ROADMAP.md diff --git a/README.md b/README.md index ad9308e0..18afdda5 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,13 @@ Check out the [full documentation](https://docs.simple-container.com) for detail ## **Contributing** -We welcome contributions! Please see our [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines on how to get involved. +We welcome contributions! Please see our [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines on how to get involved, and our [CODE_OF_CONDUCT.md](docs/CODE_OF_CONDUCT.md) for the community standards every participant is expected to uphold. + +--- + +## **Roadmap** + +See [ROADMAP.md](docs/ROADMAP.md) for current themes, release cadence, and where planned work surfaces in the [Issues](https://github.com/simple-container-com/api/issues) tracker. --- diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..de135069 --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,87 @@ +# Contributor Covenant Code of Conduct + +This is the code of conduct for the Simple Container project. +Violations should be reported to creed@simple-container.com, consistent with docs/SECURITY.md and docs/MAINTAINERS.md. +The maintainer group is responsible for enforcement according to the standard process below. + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at creed@simple-container.com. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 00000000..aaae865f --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,71 @@ +# Roadmap + +This document satisfies the OpenSSF Best Practices `documentation_roadmap` +criterion. It describes how Simple Container plans, tracks, and ships +future work in public. + +## Release cadence + +Simple Container does not gate features behind a future "version X" cut. +Production releases are cut **automatically on every merge to `main`**, +using calver tags `YYYY.M.X`. Detailed release mechanics, notes +generation, and security-fix labelling conventions are documented in +[`RELEASES.md`](RELEASES.md). + +This means there is no separate "next release date" the roadmap targets. +What ships next is what's open and approaching merge. + +## Where to read roadmap state + +| What | Where | +|---|---| +| **Feature requests + planned work** | [Issues with `feature` label](https://github.com/simple-container-com/api/issues?q=is%3Aissue+label%3Afeature) | +| **Open security work** | [Issues with `security` label](https://github.com/simple-container-com/api/issues?q=is%3Aissue+label%3Asecurity) | +| **Active work in flight** | [Open pull requests](https://github.com/simple-container-com/api/pulls) | +| **Recently shipped** | [Releases page](https://github.com/simple-container-com/api/releases) | +| **Architectural direction** | [`ARCHITECTURE.md`](ARCHITECTURE.md) + design records under [`design/`](design/) | +| **Threat model + security posture** | [`SECURITY.md`](SECURITY.md) | +| **Dependency + SCA policy** | [`DEPENDENCIES.md`](DEPENDENCIES.md) | + +## Themes for the current cycle + +The following are the broad themes the maintainers are working on. They +are not commitments — priorities shift as security reports, downstream +consumer needs, and contributor bandwidth change. For real-time state, +the Issues page above is canonical. + +1. **Supply-chain hardening.** Sigstore keyless signing, SLSA Build L3 + provenance, CycloneDX SBOM attachment, signed-release sidecars, + reachability-aware SCA gating. The pieces already shipped are + visible on the [Releases page](https://github.com/simple-container-com/api/releases); + open work surfaces under the `security` label. +2. **Cloud-integration breadth.** New cloud-provider stack templates + for AWS / GCP / Azure / Kubernetes deployment shapes. Tracked under + the `feature` label. +3. **Documentation depth.** Per-cloud guides, troubleshooting, + walkthrough examples published to + [`docs.simple-container.com`](https://docs.simple-container.com/). +4. **OpenSSF maturity.** Climbing Scorecard score + completing + bestpractices.dev attestation against the OpenSSF Baseline (project + 12886). State visible via the badges in the README. + +## How a roadmap item becomes shipped code + +1. **File an issue** with the appropriate label, or open a discussion + in the repo's Discussions tab for larger ideas. +2. **Maintainer triage** assigns priority based on user demand, security + impact, and alignment with the themes above. See + [`MAINTAINERS.md`](MAINTAINERS.md) for the decision-making + process maintainers use. +3. **Implementation** happens via PR per the contribution rules in + [`CONTRIBUTING.md`](CONTRIBUTING.md). +4. **Merge ships it** — the next push to `main` cuts a release. + +## Long-term direction + +Simple Container is a maintained product, not a hobby project. The +long-term direction is set by the maintainers (see +[`MAINTAINERS.md`](MAINTAINERS.md)) in consultation with the +downstream consumers who depend on it. Material direction changes are +discussed in the public Discussions tab before any breaking change +ships. From dc347841a6026f5ff7945a857aed0bf4e6a01204 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 23:35:45 +0400 Subject: [PATCH 09/10] docs(maintainers): document decision-making, drop internal-tracker ref Closes the OpenSSF Best Practices governance criterion (how decisions on technical direction are made). - Adds a "Decision-making" subsection under Roles: consensus via PR review (enforced by branch protection), additional reviewers for security-sensitive paths per CONTRIBUTING.md, project-lead tiebreaker for contentious calls, link to ROADMAP.md for how triage shapes shipped work. - Removes the public reference to the internal hardening tracker on the offboarding line; the public-facing maintainer-side admin checklist is enough description for outside readers. Signed-off-by: Dmitrii Creed --- docs/MAINTAINERS.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/MAINTAINERS.md b/docs/MAINTAINERS.md index 19265612..72aba9c6 100644 --- a/docs/MAINTAINERS.md +++ b/docs/MAINTAINERS.md @@ -68,6 +68,31 @@ run inside grants them, scoped per-job by GitHub Actions permissions. that pulls in additional reviewers for `pkg/security/` / `push.yaml` / `sc.sh` changes. +### Decision-making + +This section satisfies the OpenSSF Best Practices `governance` +criterion (how decisions on technical direction are made). + +- **Default rule: consensus via PR review.** Any change ships only + after a maintainer's approving review on the PR and all required + status checks (CI, signed commits, DCO sign-off) pass. Branch + protection on `main` enforces this — no maintainer self-merges + unreviewed work. +- **Security-sensitive changes** (`pkg/security/`, `push.yaml`, + `sc.sh`, anything in the SLSA / cosign / Sigstore chain) require at + least one maintainer review on top of the automated codex + Gemini + review pass triggered by `/thorough-review`. The contribution rules + in [`CONTRIBUTING.md`](CONTRIBUTING.md) describe this protocol. +- **Contentious technical decisions** (architecture, breaking changes, + security-policy shifts) are resolved by maintainer discussion in the + PR thread or repo Discussions. If consensus is not reached, the + project lead (currently [@smecsia](https://github.com/smecsia)) has + tiebreaker authority. Material direction changes are surfaced in the + Discussions tab before they ship. +- **Roadmap shaping** follows the same pattern — see + [`ROADMAP.md`](ROADMAP.md) for how issues become shipped code, and + how maintainers triage them. + ## Sensitive-resource access map The following resources have access controlled by the maintainer @@ -172,8 +197,8 @@ Maintainer offboarding additionally: rotation schedule, accelerated to "immediate" on offboarding. - Revokes Sigstore / cosign signing identities if the maintainer's GitHub workflow identity was wired into any signing path. -- Audits org-level 2FA enforcement (per - [HARDENING.md](../HARDENING.md) Phase 8 admin-UI list). +- Audits org-level 2FA enforcement against the maintainer-side admin + checklist. ## Security contact From f86f0878b41303fa252ece4b14019300bb472d60 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 18 May 2026 23:35:55 +0400 Subject: [PATCH 10/10] docs: remove internal-tracker references from public files The internal hardening tracker and control-matrix files (HARDENING.md, SECURITY-CONTROLS.md) are maintained out-of-tree while security work is in flight, so links to them produced broken navigation in the public repo. This commit replaces each reference with the public equivalent. - docs/RELEASES.md: drops the "Internal phase-by-phase hardening tracker" row from the release-notes destinations table; the cross-references section now points readers at ROADMAP.md for where planned + open security items surface in public. - docs/DEPENDENCIES.md: the image-scanning column drops the parenthetical pointer; the false-positive paragraph now correctly cites vex/openvex.json (OpenVEX not_affected statements) as the canonical channel and explicitly bans the suppression-file alternatives; the license-policy note reads "tracked internally". - docs/SECRETS-POLICY.md: removes the trailing bullet referencing the Phase 6 admin-UI checklist. - docs/CONTRIBUTING.md: the security-sensitive-change PR template now points contributors at SECURITY.md's STRIDE table + V1-V5 attack vectors instead of the internal tracker; clarifies the threat-model note should cover reachability and blast-radius. - docs/ARCHITECTURE.md: "Related security documentation" cross-refs now point only at public files (SECURITY/DEPENDENCIES/SECRETS-POLICY/ MAINTAINERS/RELEASES/ROADMAP). No code paths affected; this is a public-doc-only cleanup that keeps all working links inside the repo. Signed-off-by: Dmitrii Creed --- docs/ARCHITECTURE.md | 5 +++-- docs/CONTRIBUTING.md | 7 ++++--- docs/DEPENDENCIES.md | 10 ++++++---- docs/RELEASES.md | 5 ++--- docs/SECRETS-POLICY.md | 3 --- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 0b5128a2..35493bab 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -97,7 +97,8 @@ For deeper component-level designs, see: ## Related security documentation - [SECURITY.md](SECURITY.md) — threat model (STRIDE) + attack vectors V1–V5 + responsible-disclosure channels -- [`../HARDENING.md`](../HARDENING.md) — phase-by-phase hardening tracker (Phase 1 image hardening → Phase 8 OpenSSF visibility) -- [`../SECURITY-CONTROLS.md`](../SECURITY-CONTROLS.md) — control matrix mapping STRIDE categories to specific controls - [DEPENDENCIES.md](DEPENDENCIES.md) — dependency selection / obtaining / tracking +- [SECRETS-POLICY.md](SECRETS-POLICY.md) — secret categorisation, storage, rotation cadence - [MAINTAINERS.md](MAINTAINERS.md) — project members with access to sensitive resources +- [RELEASES.md](RELEASES.md) — release pipeline, signing chain, vuln-disclosure flow +- [ROADMAP.md](ROADMAP.md) — public roadmap state (Issues labels, themes, release cadence) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 36c6dffb..9e77ae50 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -118,9 +118,10 @@ If your change touches: - Anything in the SLSA / cosign / sigstore chain … open the PR with a **threat-model note**: which entry in -[HARDENING.md](../HARDENING.md) does this change address or affect? -Maintainers will pull in additional reviewers (codex + gemini round + -human security review) for changes here. +[`SECURITY.md`](SECURITY.md)'s STRIDE table + attack vectors V1–V5 +does this change address or affect, and what's the reachability / +blast-radius story? Maintainers will pull in additional reviewers +(codex + gemini round + human security review) for changes here. **Never disable verification** as a fix for a verification bug. If sc.sh's cosign-verify path rejects a release, the bug is in the diff --git a/docs/DEPENDENCIES.md b/docs/DEPENDENCIES.md index 17b5f281..860a2d19 100644 --- a/docs/DEPENDENCIES.md +++ b/docs/DEPENDENCIES.md @@ -27,7 +27,7 @@ selects, obtains, and tracks its dependencies." | **Go** | `go.mod` + `go.sum` | `go.sum` hashes every direct + transitive dep | `govulncheck` (reachability-aware), `osv-scanner` (via Scorecard), `trivy fs` | | **Python (docs)** | `docs/requirements.in` (sources) + `docs/requirements.txt` (compiled with `--generate-hashes`) | `pip install --require-hashes` in `push.yaml` docs-build step | `pip-audit`, Scorecard pinned-deps check | | **npm (docs examples)** | example `package*.json` files | Lockfile-aware install (`npm ci` when lockfile present, falls back to `npm install`) | Scorecard pinned-deps check | -| **Docker base images** | `Dockerfile`s + `.Dockerfile`s at repo root + example dirs | SHA digest pin: `python@sha256:401f...`, `node:22-alpine@sha256:757e...` | `trivy image` per published image (see HARDENING.md Phase 1) | +| **Docker base images** | `Dockerfile`s + `.Dockerfile`s at repo root + example dirs | SHA digest pin: `python@sha256:401f...`, `node:22-alpine@sha256:757e...` | `trivy image` per published image | | **GitHub Actions** | `.github/workflows/*` + `.github/actions/*` | Commit SHA pin with `# vX.Y.Z` comment for human-readability | Scorecard pinned-deps check; Semgrep custom rules | | **End-user installer tools** | `sc.sh` (Pulumi installer) | Tarball + SHA256 checksum verification before extract | n/a (sc.sh is shipped, not built against) | @@ -91,8 +91,10 @@ The PR pipeline runs: - Scorecard runs daily; the badge surfaces the current score A subset of findings is intentionally accepted as documented false -positives — those live in PR descriptions and in -[HARDENING.md](../HARDENING.md), never in a suppression file. +positives — those live in PR descriptions and as OpenVEX +`not_affected` statements in [`vex/openvex.json`](../vex/openvex.json), +never in a scanner-suppression file (no `.trivyignore`, no +`# nosemgrep`, no `// nolint:` for vuln findings). ## Out-of-tree dependency surface @@ -140,7 +142,7 @@ output as evidence (per OSPS-VM-04.02). License compliance is checked at PR review time. License-incompatible deps are blocked at merge by maintainer review (no automated license -scanner yet — tracked in HARDENING.md). +scanner yet — tracked internally). ## Pre-release SCA gate diff --git a/docs/RELEASES.md b/docs/RELEASES.md index 74f310fe..d76ec0f6 100644 --- a/docs/RELEASES.md +++ b/docs/RELEASES.md @@ -14,7 +14,6 @@ It satisfies the OpenSSF Best Practices `release_notes`, | **Per-release human-readable notes** | | | **Public vulnerability advisories** | | | **Public issue / PR archive (reports + responses)** | + | -| **Internal phase-by-phase hardening tracker** | [`HARDENING.md`](../HARDENING.md) (repo-side) | ## How release notes are produced @@ -135,5 +134,5 @@ searchable without additional infrastructure. boundaries the release pipeline operates within - [`DEPENDENCIES.md`](DEPENDENCIES.md) — dep selection + tracking that drives most of the `fix(deps)` security PRs -- [`../HARDENING.md`](../HARDENING.md) — phase-by-phase hardening - tracker, including the deferred-CVE log +- [`ROADMAP.md`](ROADMAP.md) — where planned work + open security + items surface in public diff --git a/docs/SECRETS-POLICY.md b/docs/SECRETS-POLICY.md index 8624e8b3..f88e4b07 100644 --- a/docs/SECRETS-POLICY.md +++ b/docs/SECRETS-POLICY.md @@ -94,6 +94,3 @@ in a private SC team vault, not published here per - [`MAINTAINERS.md`](MAINTAINERS.md) — who holds maintainer-personal credentials - [`DEPENDENCIES.md`](DEPENDENCIES.md) — dep policy -- [`../HARDENING.md`](../HARDENING.md) — Phase 6 admin-UI checklist - including Docker Hub 2FA + Cloudflare API-token audit + GCS service- - account key audit