From adc5dc2f22bb07d2e802d8db7c3fb0c76f12c890 Mon Sep 17 00:00:00 2001 From: Joshua Temple Date: Sat, 27 Jun 2026 11:54:22 -0400 Subject: [PATCH] docs: add governance, roadmap, and security docs for OpenSSF Silver Signed-off-by: Joshua Temple --- CODE_OF_CONDUCT.md | 133 ++++++++++++++++++++++ CONTRIBUTING.md | 78 ++++++++++++- GOVERNANCE.md | 184 ++++++++++++++++++++++++++++++ README.md | 17 +++ ROADMAP.md | 114 +++++++++++++++++++ docs/assurance-case.md | 207 ++++++++++++++++++++++++++++++++++ docs/security-requirements.md | 130 +++++++++++++++++++++ 7 files changed, 861 insertions(+), 2 deletions(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 GOVERNANCE.md create mode 100644 ROADMAP.md create mode 100644 docs/assurance-case.md create mode 100644 docs/security-requirements.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..82fc6fe --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ +# Contributor Covenant Code of Conduct + +## 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 email 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 +**info@stablekernel.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]. + +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]: https://github.com/mozilla/diversity +[faq]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a7b72fa..6087763 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,9 +39,83 @@ golangci-lint run ./... 5. Run `go test ./...` and `golangci-lint run ./...` before pushing. 6. Use [Conventional Commits](https://www.conventionalcommits.org/) for commit messages (`feat:`, `fix:`, `docs:`, `chore:`, ...). cascade derives changelogs and version bumps from them. -## API design +## Test policy + +cascade requires tests for changes that add or change behavior. This is a +condition of acceptance, not a suggestion. + +- **Major new functionality must ship with tests.** Any change that adds a + feature, a CLI command or flag, a manifest field, or generator behavior must + include automated tests that cover the new behavior. A pull request that adds + functionality without tests will be asked to add them before it can merge. +- **Generator features need an end-to-end scenario.** New manifest fields and + generator features require an `e2e/` scenario that exercises the generated + workflow, not only a unit test asserting on generated output. A generator + change with no `e2e/` scenario does not meet the bar. +- **Bug fixes should include a regression test.** When you fix a bug, add a test + that fails before your fix and passes after it, so the bug cannot return + unnoticed. +- **Tests run in CI on every pull request.** The test suite and the linter run + automatically on each pull request and must pass before merge. + +Run the suites locally before pushing: -Public APIs follow a functional-options style: required inputs are positional and optional or extensible behavior arrives as a variadic `...Option` tail, so new capability is additive and never a breaking signature change. Cross-cutting concerns are small interfaces with no-op defaults rather than forced dependencies. +```bash +# Unit tests +go test ./... + +# End-to-end tests (requires Docker; uses testcontainers + gitea) +cd e2e && go test -v -timeout 20m ./... +``` + +The normal inner loop is `go build ./...`, `go test ./...`, and the linter; the +full Docker-backed end-to-end suite is run when your change affects generated +workflow behavior. + +## Coding standard + +cascade follows standard Go style, enforced automatically. Contributions are +expected to meet it. + +- **Formatting.** Code must be `gofmt`-clean. Use `gofmt` (or `goimports`) before + committing. +- **Linting.** cascade uses `golangci-lint` as its coding standard. Your change + must pass it with no new findings: + + ```bash + golangci-lint run ./... + ``` + + The linter runs in CI and is part of the merge bar. Treat its warnings as + errors: do not merge changes that introduce new lint findings, and do not + silence findings with blanket suppressions. Narrowly scoped, justified + suppressions are acceptable only when a finding is a genuine false positive. +- **Idiomatic Go.** Follow effective, idiomatic Go: clear naming, small focused + functions, errors wrapped with context, no unused exports. The build must be + warning-free. +- **API design.** Public APIs use a functional-options style: required inputs are + positional and optional or extensible behavior arrives as a variadic + `...Option` tail, so new capability is additive and never a breaking signature + change. Cross-cutting concerns are small interfaces with no-op defaults rather + than forced dependencies. + +## Contribution requirements summary + +To be accepted, a contribution must: + +1. Be a single logical change in its own pull request, branched from `main`. +2. Sign off every commit under the + [Developer Certificate of Origin](https://developercertificate.org/) + (`git commit -s`). +3. Use [Conventional Commits](https://www.conventionalcommits.org/) for commit + messages. +4. Include tests for new or changed behavior, with an `e2e/` scenario for + generator and manifest changes. +5. Pass `go test ./...` and `golangci-lint run ./...`. +6. Keep the manifest schema additive: new fields are optional with sensible + defaults; existing fields are not removed or renamed within a major version. + +By participating you agree to the [Code of Conduct](./CODE_OF_CONDUCT.md). ## Reporting bugs diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 0000000..0402682 --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,184 @@ +# Governance + +This document describes how cascade is governed: who makes decisions, how those +decisions are made, and how the project continues if the maintainer becomes +unavailable. It is written to be honest about the project's current scale rather +than to describe an aspirational structure that does not yet exist. + +## Project status + +cascade is an open-source project published under the `stablekernel` +organization and licensed under Apache-2.0. Today it is a single-maintainer +project. One person holds the maintainer role and is responsible for the +direction, review, and release of the codebase. This is a normal and supported +shape for a focused tool, and the rest of this document is written with that +reality in mind. + +## Roles and responsibilities + +### Maintainer + +The maintainer is the steward of the project. There is currently one maintainer. +The maintainer is responsible for: + +- Setting and communicating the project's direction, recorded in + [ROADMAP.md](./ROADMAP.md). +- Reviewing and merging pull requests. +- Triaging issues and security reports. +- Cutting releases and managing release signing keys and credentials. +- Enforcing the [Code of Conduct](./CODE_OF_CONDUCT.md). +- Keeping the documentation, security policy, and governance current. + +The maintainer has write access to the repository and custody of the release +signing material and the credentials used by the release pipeline. + +### Contributors + +Anyone who opens an issue, proposes a change, improves documentation, or helps +others is a contributor. Contributors do not need any special permission to +participate. Contributions arrive as pull requests and are accepted under the +[Developer Certificate of Origin](https://developercertificate.org/) as +described in [CONTRIBUTING.md](./CONTRIBUTING.md). Contributors do not have +write access; their changes land through maintainer review. + +### Users + +Users adopt cascade in their own repositories. Their feedback, bug reports, and +adoption experiences are a primary input to the roadmap. Users are encouraged to +open issues and discussions. + +## How decisions are made + +cascade uses a benevolent-maintainer model. The maintainer is the final +decision-maker, and decisions are made in the open wherever practical. + +- **Routine changes** (bug fixes, documentation, additive manifest fields, + internal refactors) are decided through normal pull-request review. The + maintainer reviews against the project's correctness, test, and guardrail bar + and merges when it passes. +- **Significant changes** (new manifest surface, changes to the generated + workflow contract, anything that affects backward compatibility) start as a + GitHub issue that states the problem and the proposed approach before code is + written. This gives users a chance to weigh in. The maintainer makes the final + call and records the rationale on the issue or pull request. +- **Disagreements** are resolved through discussion on the relevant issue or + pull request. When consensus is not reached, the maintainer decides and + documents the reasoning so the decision is reviewable later. + +### Proposing a change + +1. Open an issue describing the problem and, if you have one, a proposed + solution. For anything beyond a small fix, do this before writing code. +2. Discuss the approach. The maintainer will confirm direction or suggest an + alternative. +3. Submit a pull request that follows [CONTRIBUTING.md](./CONTRIBUTING.md), + including tests for new functionality. +4. The maintainer reviews, requests changes if needed, and merges. + +## Compatibility and release authority + +The maintainer is the authority on backward compatibility. cascade keeps the +manifest schema additive within a major version: new fields are optional, and no +existing field is removed or renamed before the next major version. The release +process and version policy are described in +the [architecture documentation](https://stablekernel.github.io/cascade/architecture/) +and the schema versioning guide. + +## Changing this document + +This governance model can change as the project grows, for example by adding +maintainers or moving to a formal council. Changes to governance are themselves +proposed and discussed through a pull request against this file. + +## Continuity and succession + +A single-maintainer project carries an obvious risk: if the maintainer becomes +unavailable, the project can stall. This section describes how cascade is set up +to survive the loss of any one person and to keep operating within about a week. +The plan is deliberately concrete about what exists today and what is a +maintainer follow-up. + +### What keeps working without the maintainer + +cascade is designed so that most of the project's value does not depend on the +maintainer being present: + +- The source, history, license, and documentation are public in Git. Anyone can + clone, fork, build, and run cascade. The Apache-2.0 license permits a fork to + continue the project. +- Released binaries are published as GitHub Releases and the module is available + through the Go module proxy, so existing users are unaffected by a gap in + maintenance. +- The build, test, and release pipeline is defined as code in the repository, so + a successor with the right credentials can reproduce a release by following the + documented process rather than reconstructing tribal knowledge. + +### Succession + +The intent is for the project to have a designated backup maintainer who can +step in. Until a second maintainer is formally added, succession follows this +order: + +1. **Designated backup maintainer.** The maintainer names a backup who has, or + can be granted, the access described below. The backup is empowered to triage + issues, accept changes, and cut releases. +2. **Organization owners.** Because the repository lives under the + `stablekernel` GitHub organization, organization owners can restore + administrative access to the repository, grant write access to a successor, + and re-establish release credentials if the maintainer is unreachable. +3. **Community fork.** As a last resort, the Apache-2.0 license guarantees the + community can fork and continue the project. This is the floor, not the plan. + +### Operating the project during a handover + +A successor with repository write access and the credentials below can perform +every routine maintainer task within a week: + +- **Issues.** Create, label, triage, and close issues through the GitHub UI. +- **Changes.** Review and merge pull requests through the GitHub UI. The + contribution bar (tests, lint, guardrails) is documented in + [CONTRIBUTING.md](./CONTRIBUTING.md) so a successor can apply it consistently. +- **Releases.** Cut a release by following the documented release process. The + pipeline is code in `.github/workflows`; the human inputs are the signing key + and the pipeline credentials described next. + +### Key and access custody + +The items below are what a successor needs. Concrete custody arrangements are +maintainer follow-ups and are intentionally not embedded in this file. + +- **Repository administration.** Held by the maintainer and recoverable by + `stablekernel` organization owners. +- **Release signing material.** The private signing key used for releases lives + only as the `CASCADE_RELEASE_GPG_KEY` repository secret and is never on the + distribution site. The key has no passphrase: a passphrase would be stored as a + repository secret too, the same trust boundary as the key, so it would add a + maintained item without adding protection. The key is disposable: a successor + who cannot reach the existing secret simply generates a new signing key, + replaces the secret, and publishes the new public key. No key escrow is needed. +- **Release pipeline credentials.** Any tokens or secrets the release pipeline + needs are stored as GitHub Actions secrets on the repository or organization, + which organization owners can rotate. + *Maintainer follow-up: document each required secret and confirm an + organization owner can rotate it.* +- **Public verification material.** The public signing key and the verification + procedure are published with the project so users can verify releases + regardless of who cut them. The GPG public key is committed at + [docs/cascade-release-public-key.asc](./docs/cascade-release-public-key.asc) + and the verification steps are documented in + [docs/release-verification.md](./docs/release-verification.md). + +### Maintainer follow-ups for full continuity + +- [x] Publish the public signing key and the user-side verification procedure. + The GPG public key is committed at + [docs/cascade-release-public-key.asc](./docs/cascade-release-public-key.asc) + and the procedure is documented in + [docs/release-verification.md](./docs/release-verification.md). +- [x] Confirm `stablekernel` organization owners can restore repository + administration if the maintainer is unreachable. The organization has + multiple owners and the repository has multiple administrators, so + repository access is not a single point of failure. +- [ ] Name a backup maintainer with explicit authority to triage, merge, and + release. +- [ ] Document every release-pipeline secret and confirm an owner can rotate it. diff --git a/README.md b/README.md index 945329d..d067925 100644 --- a/README.md +++ b/README.md @@ -371,6 +371,23 @@ Full flag reference: [CLI reference](https://stablekernel.github.io/cascade/cli- --- +## Project governance + +How cascade is run, where it is going, and how it is designed and secured: + +| Document | Description | +|---|---| +| [Governance](./GOVERNANCE.md) | Roles, decision model, and continuity and succession plan | +| [Roadmap](./ROADMAP.md) | Public roadmap and direction | +| [Code of Conduct](./CODE_OF_CONDUCT.md) | Community standards and reporting | +| [Architecture](https://stablekernel.github.io/cascade/architecture/) | System design, components, and trust boundaries | +| [Security requirements](./docs/security-requirements.md) | Security goals the project holds itself to | +| [Assurance case](./docs/assurance-case.md) | Threat model and the argument that cascade is built and operated securely | + +For private vulnerability reporting, see [SECURITY.md](./SECURITY.md). + +--- + ## Roadmap to stable cascade is functional and self-hosted; its own releases page shows the full pipeline running end to end. The remaining work before the v1.0.0 schema freeze falls into two areas: diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..441d6bb --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,114 @@ +# Roadmap + +This roadmap describes where cascade is headed over roughly the next year. It is +a statement of intent, not a contract: priorities shift as users adopt cascade +and report what they need. Dated, issue-level work is tracked in +[GitHub Issues](https://github.com/stablekernel/cascade/issues); this document +is the higher-level picture. + +## What cascade is + +cascade is a compiler for release and promotion pipelines. You describe your +environments, builds, deploys, and release rules in one manifest, and cascade +generates the GitHub Actions workflows that run them. The generated workflows are +plain YAML you commit and review; cascade never sits between your repository and +your runners at deploy time. This "compile, do not control" stance is the +organizing principle of the project, and it shapes everything on this roadmap. + +## Guiding principles + +These hold across every release and will not change without a major-version +discussion: + +- **Compiler, not a control plane.** cascade produces workflows you own and run. + It does not run a hosted service, hold your credentials, or act as a + deployment broker at runtime. +- **The manifest is the source of truth.** Configuration and live deployment + state live in one reviewed file in your repository. +- **Additive, compatible evolution.** New manifest fields are optional with + sensible defaults. Existing fields are not removed or renamed within a major + version. +- **Your logic stays yours.** Build and deploy steps are your reusable + workflows, called through a documented contract. cascade is a metadata courier + between stages. + +## Near-term focus: hardening toward a stable v1 + +The current series is the 0.x line. The goal of this period is to close the gap +between what the manifest can describe and what the generator emits, and to +raise the project's assurance level so a 1.0 release means a frozen, dependable +manifest contract. Planned work includes: + +- **Complete the generator surface.** A few GitHub Actions capabilities are + modeled in the manifest shape but not yet fully emitted: environment gates, + OIDC token configuration, and per-environment runner overrides. Closing these + is on the direct path to v1. +- **Deepen end-to-end coverage.** Continue expanding the live and containerized + end-to-end suites so generated workflows are exercised against real GitHub + behavior, including edge cases such as empty builds, cross-repo coordination, + hotfix-to-any-environment, and rollback to a previous version. +- **Raise and publish test coverage.** Grow statement coverage and report it + publicly so adopters can see the project's quality signal. +- **Documentation and onboarding.** Keep the getting-started, adoption, + callback-contract, and hardening guides accurate as the surface grows, and + smooth the path from an existing pipeline to a cascade-generated one. + +Supply-chain assurance is now in place: release checksums are signed with cosign +keyless signing and a GPG detached signature, SLSA build provenance is attested, +the build is reproducible, and users can verify what they download using the +published GPG key and the procedure in +[docs/release-verification.md](./docs/release-verification.md). + +## The v1 milestone + +v1.0.0 marks the point where the manifest schema is frozen as a stable contract. +After v1: + +- Existing manifest fields keep their meaning across the entire v1 series. +- New capability arrives as new optional fields, never as breaking changes to + what already works. +- A manifest that validates against v1 keeps validating for the life of v1. + +The schema field shapes were established early as the v1 baseline. Minor releases +before v1 may add optional fields; they will not remove or rename existing ones. + +## Looking past v1 + +These are directions under consideration, not commitments. They will be shaped +by what adopters actually ask for: + +- Richer promotion policies and gating expressed declaratively in the manifest. +- Broader patterns for cross-repo and multi-artifact coordination. +- Better preview and explanation of what a generated pipeline will do before it + runs. +- Quality-of-life improvements to scaffolding and migration from existing + pipelines. + +## What cascade will not do + +Saying no keeps the tool coherent. cascade intentionally does not, and does not +plan to: + +- **Become a hosted service or control plane.** cascade will not run your + deployments, hold your secrets, or insert a runtime broker between your + repository and your runners. It compiles workflows and steps out of the way. +- **Own your build and deploy logic.** cascade will not replace your build + scripts or deploy tooling. Those stay in your reusable workflows; cascade + orchestrates around them through the callback contract. +- **Target CI systems other than GitHub Actions.** cascade compiles to GitHub + Actions. Supporting a second CI backend is out of scope for the foreseeable + future. +- **Touch your registries or deployment targets directly.** cascade passes + artifact identifiers and versions between stages. It does not push images, + publish packages, or call cloud APIs on your behalf. +- **Replace conventional commits with a bespoke versioning scheme.** cascade + derives versions and changelogs from conventional commits by design. +- **Break the manifest contract for convenience.** Backward compatibility within + a major version is a hard rule, not a preference. + +## How this roadmap changes + +This document is revised as the project moves. Proposed changes to direction are +discussed in [GitHub Issues](https://github.com/stablekernel/cascade/issues) and +land through pull requests against this file, following the process in +[GOVERNANCE.md](./GOVERNANCE.md). diff --git a/docs/assurance-case.md b/docs/assurance-case.md new file mode 100644 index 0000000..8e57276 --- /dev/null +++ b/docs/assurance-case.md @@ -0,0 +1,207 @@ +# Assurance case + +An assurance case is a structured argument, backed by evidence, that a system is +acceptably secure for its intended use. This document presents cascade's +assurance case: the claim, the threat model and trust boundaries that scope it, +the argument that secure-design principles are applied, and the argument that +common implementation weaknesses are countered. + +It complements the [security requirements](./security-requirements.md), which +state what is in and out of scope, and the [security policy](../SECURITY.md), +which covers reporting and supported versions. + +## Top-level claim + +cascade can be adopted without introducing security risk beyond the GitHub and +cloud configuration a user already controls, provided the user follows the +documented hardening guidance. Specifically: + +1. The workflow YAML cascade generates does not introduce injection or + privilege-escalation vulnerabilities of its own. +2. cascade does not handle, store, or leak user secrets. +3. cascade's released binaries can be verified to come from the project, + unmodified. + +The rest of this document argues each part and points at the evidence. + +## System and intended use + +cascade is a Go command-line tool that compiles a declarative manifest into +GitHub Actions workflows. The user commits those workflows and runs them on their +own runners. cascade also runs as the per-step CLI invoked from inside the +generated workflows. cascade is not a service: it has no hosted component, no +runtime broker, and no custody of user credentials. Its intended use is by teams +on GitHub Actions who want to promote built artifacts through a chain of +environments from a trunk-based flow. + +## Trust boundaries + +The boundaries that scope this assurance case are: + +- **Manifest authoring boundary.** The manifest is authored and reviewed by the + user in their own repository, under branch protection. cascade treats the + manifest as trusted configuration but still validates it against the schema and + treats its string values as untrusted data when interpolating them into + generated workflows. +- **Generated-workflow boundary.** The output of generation is YAML the user + reviews and commits. Once committed, it runs under the user's GitHub + permissions, environment gates, and token scopes. cascade's responsibility ends + at producing safe YAML; the runtime authority is GitHub's and the user's. +- **Same-organization, shared-token boundary.** Cross-repo coordination assumes + repositories within one organization that trust each other to the extent of a + user-provisioned dispatch token. That token is the boundary. cascade does not + add independent authentication between coordinating repositories; see + [security requirements](./security-requirements.md). +- **Distribution boundary.** Released binaries cross from the project to users + over HTTPS as GitHub Releases whose `checksums.txt` is signed with both cosign + keyless signing and a GPG detached signature, with SLSA build provenance + attested for the artifacts. The private GPG signing key never lives on the + distribution site, so compromise of the distribution channel does not let an + attacker forge a verifiable release. The verification procedure is in + [docs/release-verification.md](./release-verification.md) and the published GPG + public key is committed at + [docs/cascade-release-public-key.asc](./cascade-release-public-key.asc). + +## Threat model + +The relevant threat actors and the threats cascade defends against: + +### T1: Injection through manifest or runtime values into generated workflows + +An attacker who can influence a value that flows into a generated workflow (a +manifest field, a branch name, a commit subject, an artifact identifier, an +external-update input) tries to break out of the intended context and execute +arbitrary commands or workflow expressions. + +**Mitigation.** cascade treats such values as untrusted when generating +workflows and when emitting GitHub Actions step outputs. Generated steps are +constructed so that interpolated values cannot escape into shell or workflow +expression evaluation. Injection hardening for these paths has shipped and is +covered by tests. This is the primary attack surface for a workflow compiler and +receives the most attention. + +### T2: A malicious or compromised coordinating repository + +In the cross-repo model, a coordinating repository dispatches updates to the +primary. A compromised one could try to write bad state or trigger unintended +promotions. + +**Mitigation and scoping.** This is bounded by the same-organization, +shared-token trust model. The dispatch token and the GitHub permissions around it +are the control. cascade serializes concurrent state writes so a malicious update +cannot corrupt the shared manifest through a race, but it does not, by design, +independently authenticate coordinating repositories. Users constrain blast +radius with least-privilege tokens, environment protection, and per-job +permissions, as documented in the hardening guide. This boundary is stated +plainly as out of scope for cascade-level authentication. + +### T3: Tampered distribution + +An attacker substitutes a malicious binary for a cascade release, or tampers with +a release in transit. + +**Mitigation.** Releases are distributed over HTTPS and the release checksums, +which cover the archives, are cryptographically signed with cosign keyless +signing and a GPG detached signature, alongside SLSA build provenance attested +through GitHub. The GPG public key is published at +[docs/cascade-release-public-key.asc](./cascade-release-public-key.asc) and the +verification procedure is documented in +[docs/release-verification.md](./release-verification.md). The private GPG key is +held off the distribution site. Users can verify integrity before running a +binary. + +### T4: Unsafe or undefined behavior on incompatible input + +A manifest written for a different schema version is processed by a CLI that does +not understand it, producing undefined or unsafe output. + +**Mitigation.** Every CLI invocation enforces the schema-version compatibility +check and fails closed with a clear error rather than guessing. + +### T5: Secret exposure + +cascade inadvertently reads, logs, or transmits a user secret. + +**Mitigation.** cascade does not read or handle secrets. It passes only +non-secret metadata (artifact identifiers, versions, SHAs) between stages. +Secrets are GitHub Actions secrets referenced by the user's own callbacks, which +cascade never inspects. + +### Out-of-scope threats + +Consistent with the [security requirements](./security-requirements.md): the +security of the user's GitHub and cloud configuration, the behavior of the user's +own callbacks, inter-repository authentication beyond the shared token, the +user's registries and deployment targets, and runtime secrets management are not +cascade's responsibility. They are stated as out of scope so the boundary is +unambiguous. + +## Argument: secure-design principles are applied + +- **Least privilege.** cascade holds no standing credentials and runs with only + the permissions the user grants the generated workflows. It supports + SHA-pinning of the actions it manages and least-privilege per-job permissions + in generated workflows so callbacks receive only the access they need. +- **Minimized attack surface.** cascade is a CLI with no network service, no + listening port, and no persistent runtime. Its only external surfaces are the + manifest it reads and the GitHub API it calls during a run. +- **Separation of responsibility.** Build and deploy logic stays in the user's + callbacks, isolated behind a documented `workflow_call` contract. cascade is a + metadata courier and never reaches into callback logic or touches deployment + targets directly. +- **Fail closed.** Schema-version mismatches and invalid manifests are rejected + rather than processed with undefined behavior. +- **Treat input as untrusted.** Manifest and runtime values are validated and + handled as data when interpolated into generated workflows, regardless of their + apparent trust level. +- **Defense in depth.** cascade's safe generation sits on top of the user's + GitHub controls (branch protection, environment gates, scoped tokens), and the + hardening guide directs users to enable those layers. + +## Argument: common implementation weaknesses are countered + +- **Injection (the dominant class for a workflow compiler).** Values + interpolated into generated workflows and step outputs are handled so they + cannot escape into shell or workflow-expression execution. This path is + hardened and tested. +- **Memory-safety weaknesses.** cascade is written in Go, a memory-safe language + with bounds checking and no manual memory management, which removes the classic + buffer-overflow and use-after-free weakness classes by construction. (For this + reason the OpenSSF crypto and unsafe-language criteria are not applicable.) +- **Supply-chain weaknesses.** Dependencies are pinned through Go modules with a + checksum database; CI runs static analysis (golangci-lint and CodeQL) and + OpenSSF Scorecard; Dependabot monitors the Go modules and GitHub Actions for + known vulnerabilities and proposes updates; the actions used in the project's + own workflows are SHA-pinned; and release checksums are signed with cosign + keyless signing and a GPG detached signature, with SLSA build provenance and a + documented verification procedure. Coverage is measured and reported. +- **Concurrency weaknesses.** Concurrent writes to the shared manifest state are + serialized so they cannot corrupt state through a race. +- **Undefined behavior on bad input.** The schema validator and schema-version + check reject malformed or incompatible manifests with clear errors. + +## Evidence + +- Source, history, and tests are public in the repository. +- Static analysis (golangci-lint, CodeQL) and OpenSSF Scorecard run in CI, and + Dependabot tracks the Go modules and GitHub Actions; lint is part of the + pre-merge bar. +- Unit, containerized end-to-end, and live fleet end-to-end suites exercise the + generated workflows; see the + [architecture documentation](https://stablekernel.github.io/cascade/architecture/). +- The OpenSSF Scorecard badge and the project's CI status are linked from the + README. +- The release process signs the release checksums with cosign keyless signing + and a GPG detached signature, attests SLSA build provenance, and produces a + reproducible build. The published GPG public key + ([docs/cascade-release-public-key.asc](./cascade-release-public-key.asc)) and + the documented verification procedure + ([docs/release-verification.md](./release-verification.md)) let users verify + what they download. + +## Maintaining this case + +This assurance case is revisited as the threat surface changes, for example when +new manifest capability widens what flows into generated workflows. Changes land +through pull requests against this file, following the process in +[GOVERNANCE.md](../GOVERNANCE.md). diff --git a/docs/security-requirements.md b/docs/security-requirements.md new file mode 100644 index 0000000..19a2e9f --- /dev/null +++ b/docs/security-requirements.md @@ -0,0 +1,130 @@ +# Security requirements + +This document states what users can and cannot expect from cascade with respect +to security. It complements the [security policy](../SECURITY.md), which covers +supported versions and how to report a vulnerability, and the +[hardening guide](https://stablekernel.github.io/cascade/security/hardening/), +which gives a step-by-step checklist for configuring GitHub safely. Read this +document to understand the trust model and the boundary of cascade's +responsibility before adopting it. + +## What cascade is, in security terms + +cascade is a build-time compiler. It reads a manifest and emits GitHub Actions +workflow YAML that you commit to your own repository and run on your own runners. +cascade is not a hosted service, does not run at deploy time, does not hold your +credentials, and does not act as a broker between your repository and your +deployment targets. This shapes the entire security model: the workflows cascade +generates run with whatever permissions, tokens, branch protection, and +environment gates you configure in your own GitHub organization. + +Securing a cascade deployment is therefore a shared responsibility. cascade is +responsible for generating safe workflow YAML and for the integrity of its own +released binaries. You are responsible for the GitHub and cloud configuration the +generated workflows run within. + +## Trust model + +### Same-organization, shared-token model + +cascade's cross-repo coordination assumes a same-organization trust model. When a +primary repository owns an environment chain for artifacts built in other +repositories, those repositories coordinate through a dispatch token that you +provision. That token is the trust boundary. cascade assumes the repositories +participating in a cascade are operated by the same organization and trust each +other to the extent that the shared token allows. cascade does not add an +independent authentication or authorization layer on top of GitHub's; the +identity and permission model is GitHub's, scoped by the tokens and environment +protections you configure. + +This means callback authentication between coordinating repositories is out of +scope for cascade. If you need to constrain what a coordinating repository can +do, you do it with GitHub's mechanisms: least-privilege tokens, environment +protection rules, branch protection, and per-job permissions on the callbacks. + +### What you control + +The security of a running cascade pipeline is determined by configuration you +own: + +- The dispatch token and its scope. +- Branch protection on the trunk branch. +- GitHub environment protection rules and required reviewers on deployment + environments. +- The permissions block and secrets available to your build and deploy + callbacks. +- Whether generated workflows pin actions by SHA (cascade supports + `pin_mode: sha` to emit SHA-pinned references for the actions it manages). + +The [hardening guide](https://stablekernel.github.io/cascade/security/hardening/) +walks through configuring each of these. + +### What cascade controls + +- The correctness and safety of the workflow YAML it generates, including + hardening against injection in the values it interpolates into generated + workflows. +- The integrity of cascade's own released binaries, distributed over HTTPS as + GitHub Releases whose checksums (covering the archives) are signed with cosign + keyless signing and a GPG detached signature, with the verification procedure + documented in [release-verification.md](./release-verification.md) and the GPG + public key published at + [cascade-release-public-key.asc](./cascade-release-public-key.asc). +- Enforcing the schema-version compatibility check so a CLI version refuses to + operate on a manifest shape it does not understand, failing closed with a + clear error rather than producing undefined output. + +## In scope + +cascade takes responsibility for: + +- **Safe generation.** Generated workflows are constructed so that values flowing + from the manifest and from the runtime context are handled safely, including + guarding against shell and workflow-expression injection in generated steps. +- **No silent credential handling.** cascade does not read, store, or transmit + your secrets. Secrets are GitHub Actions secrets that your callbacks reference; + cascade only passes non-secret metadata (artifact identifiers, versions, SHAs) + between stages. +- **Integrity of distribution.** Released binaries are published over HTTPS, and + the release checksums that cover the archives are signed with both cosign + keyless signing and a GPG detached signature, accompanied by SLSA build + provenance. The published GPG public key + ([cascade-release-public-key.asc](./cascade-release-public-key.asc)) and the + step-by-step verification procedure + ([release-verification.md](./release-verification.md)) let you verify what you + downloaded. The private GPG signing key is never stored on the distribution + site. +- **Fail-closed version handling.** A manifest with an incompatible schema + version is rejected rather than processed with undefined behavior. +- **Coordinated vulnerability response.** Vulnerabilities reported privately are + triaged and fixed under the timelines in the [security policy](../SECURITY.md). + +## Out of scope + +The following are explicitly not cascade's responsibility. Treating them as such +would be a security mistake: + +- **Your GitHub and cloud configuration.** Branch protection, environment gates, + token scoping, OIDC trust policies, and runner security are yours to configure. + cascade generates workflows that respect them, but cannot enforce them on your + behalf. +- **The contents and behavior of your callbacks.** cascade calls your build and + deploy workflows through a documented contract and never inspects or modifies + their logic. The security of what those workflows do (what they pull, what they + push, what they have access to) is yours. +- **Inter-repository authentication beyond the shared token.** cascade assumes a + same-organization, shared-token trust model. It does not authenticate + coordinating repositories independently; that boundary is the token you + provision and the GitHub permissions around it. +- **Your registries and deployment targets.** cascade never touches your + container registry, package registry, or deployment target directly. It is a + metadata courier. +- **Runtime secrets management.** cascade does not manage, rotate, or store + secrets. Use GitHub Actions secrets and your organization's secret management. + +## Reporting + +If you find a security issue in cascade itself (for example a way to make the +generator emit unsafe workflow YAML, or a flaw in release integrity), report it +privately as described in the [security policy](../SECURITY.md). Do not open a +public issue for security vulnerabilities.