{"id":46762881,"url":"https://github.com/sufield/stave","last_synced_at":"2026-03-09T22:23:35.121Z","repository":{"id":342617286,"uuid":"1174561309","full_name":"sufield/stave","owner":"sufield","description":"A configuration safety evaluator that detects cloud resources remaining unsafe for too long, using only local config snapshots without using any cloud credentials.","archived":false,"fork":false,"pushed_at":"2026-03-06T19:07:47.000Z","size":5166,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-06T19:26:47.107Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sufield.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-06T15:28:41.000Z","updated_at":"2026-03-06T19:07:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sufield/stave","commit_stats":null,"previous_names":["sufield/stave"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/sufield/stave","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sufield%2Fstave","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sufield%2Fstave/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sufield%2Fstave/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sufield%2Fstave/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sufield","download_url":"https://codeload.github.com/sufield/stave/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sufield%2Fstave/sbom","scorecard":{"id":1244461,"data":{"date":"2026-03-06T19:07:55Z","repo":{"name":"github.com/sufield/stave","commit":"cb45a910a7695062347ad18e9f9bebdaeb48d8b7"},"scorecard":{"version":"v5.3.0","commit":"c22063e786c11f9dd714d777a687ff7c4599b600"},"score":4.9,"checks":[{"name":"Maintained","score":0,"reason":"project was created within the last 90 days. Please review its contents carefully","details":["Warn: Repository was created within the last 90 days."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#packaging"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dependency-update-tool"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#security-policy"}},{"name":"Code-Review","score":0,"reason":"Found 0/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: topLevel 'contents' permission set to 'read': .github/workflows/ci.yml:11","Info: topLevel 'contents' permission set to 'read': .github/workflows/coverage.yml:10","Warn: topLevel 'contents' permission set to 'write': .github/workflows/release.yml:10","Info: topLevel 'actions' permission set to 'read': .github/workflows/release.yml:12","Info: topLevel permissions set to 'read-all': .github/workflows/scorecard.yml:10","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":10,"reason":"all dependencies are pinned","details":["Info:  22 out of  22 GitHub-owned GitHubAction dependencies pinned","Info:   6 out of   6 third-party GitHubAction dependencies pinned","Info:   2 out of   2 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#sast"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#branch-protection"}},{"name":"Contributors","score":0,"reason":"project has 0 contributing companies or organizations -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#contributors"}},{"name":"CI-Tests","score":2,"reason":"1 out of 4 merged PRs checked by a CI test -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#ci-tests"}}]},"last_synced_at":"2026-03-06T21:12:21.582Z","repository_id":342617286,"created_at":"2026-03-06T21:12:21.582Z","updated_at":"2026-03-06T21:12:21.582Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30314617,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T20:05:46.299Z","status":"ssl_error","status_checked_at":"2026-03-09T19:57:04.425Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-03-09T22:23:34.469Z","updated_at":"2026-03-09T22:23:35.076Z","avatar_url":"https://github.com/sufield.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stave\n\nA configuration analysis engine that detects insecure configurations in your cloud environment using only local configuration snapshots — no cloud credentials required.\n\n[Docs](docs/index.md) | [Quickstart](docs/time-to-first-finding.md) | [Releases](https://github.com/sufield/stave/releases) | [Security](SECURITY.md) | [Contributing](CONTRIBUTING.md)\n\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/sufield/stave/badge)](https://securityscorecards.dev/viewer/?uri=github.com/sufield/stave)\n[![Go Report Card](https://goreportcard.com/badge/github.com/sufield/stave)](https://goreportcard.com/report/github.com/sufield/stave)\n[![codecov](https://codecov.io/gh/sufield/stave/branch/main/graph/badge.svg)](https://codecov.io/gh/sufield/stave)\n\n## Why Stave exists\n\nMost existing S3 security tools share a blind spot. They treat Block Public Access as the definitive signal for public exposure. When BPA is enabled, buckets pass — even when legacy ACLs still grant public read or write. AWS Trusted Advisor is the most prominent example.                                                                     \n                                                                  \nStave catches what these tools miss. It evaluates the full configuration surface — ACLs, bucket policies, and BPA settings — against composable predicate logic, not a single-flag heuristic.\n\nIt works from local observation snapshots: offline, deterministic, and credential-free. No API calls, no runtime agents, no network access at scan time.\n\n## What Stave does\n\nStave reads point-in-time configuration snapshots and evaluates them against YAML-defined safety controls:\n\n- **43 built-in S3 controls** — public exposure, ACL escalation, encryption, versioning, lifecycle, object lock, logging, governance, takeover prevention\n- **Unsafe duration tracking** — detects how long assets remain misconfigured across multiple snapshots\n- **Deterministic output** — same input always produces same findings\n- **Enforcement artifacts** — generates fix plans with specific remediation actions\n\nAll evaluation runs locally. No cloud credentials. No network access. Air-gapped by design.\n\n## Quick start\n\n### Install\n\n```bash\nbrew tap sufield/tap \u0026\u0026 brew install stave\n```\n\nOr build from source:\n\n```bash\ngit clone https://github.com/sufield/stave.git\ncd stave \u0026\u0026 make build\n```\n\n### First finding in 60 seconds\n\n```bash\nstave demo\ncat stave-report.json\n```\n\nExpected output:\n\n```\nFound 1 violation: CTL.S3.PUBLIC.001\nAsset: s3://demo-public-bucket\nEvidence: BlockPublicAccess=false, ACL=public-read\nFix: enable account/bucket Block Public Access + deny public principals\n```\n\nCompare with a safe configuration:\n\n```bash\nstave demo --fixture known-good\n```\n\n### Full workflow\n\n```bash\nstave init --profile aws-s3\nstave validate\nstave apply --format json \u003e output/evaluation.json\nstave diagnose\n```\n\n## How it works\n\n```\nCapture → Validate → Apply → Act\n\n1. Capture    Export asset configurations as JSON snapshots\n2. Validate   Check inputs are well-formed and complete\n3. Apply      Evaluate snapshots against safety controls, produce findings\n4. Act        Review findings, remediate, re-evaluate\n```\n\nSnapshots must conform to the [observation contract](docs/observation-contract.md). You need at least two snapshots (two points in time) for Stave to calculate unsafe duration windows.\n\n## How Stave compares\n\n| Category | Examples | No credentials needed | Offline snapshots | Deterministic | Duration aware | Enforcement |\n|----------|----------|:---:|:---:|:---:|:---:|:---:|\n| CSPM | AWS Config, Wiz, Prisma, Prowler | ❌ | ❌ | ❌ | ❌ | ⚠️ |\n| IaC policy | OPA, Checkov, tfsec | ✅ | ❌ | ✅ | ❌ | ❌ |\n| S3 auditors | ScoutSuite, s3audit, CloudMapper | ❌ | ❌ | ❌ | ❌ | ❌ |\n| **Stave** | | ✅ | ✅ | ✅ | ✅ | ✅ |\n\nThink of it as:\n\n| Tool type | Analogy |\n|-----------|---------|\n| CSPM | Runtime cloud scanner |\n| IaC policy | Template linter |\n| S3 auditor | Exposure enumerator |\n| **Stave** | Snapshot safety evaluator |\n\n## Security model\n\n- **Zero network access** — evaluation never contacts external services\n- **No credentials** — works on exported snapshots, not live APIs\n- **Deterministic output** — `--now` flag pins evaluation time for reproducibility\n- **Output sanitization** — `--sanitize` scrubs asset identifiers from findings\n- **Signed releases** — SHA256 checksums signed with Sigstore cosign\n- **Build provenance** — GitHub-native SLSA attestation on release archives\n- **SBOM** — SPDX Software Bill of Materials attached to every release\n\nDetails: [Security and Trust](docs/trust/01-security-and-trust.md) | [Threat Model](docs/security/threat-model.md) | [Verify a Release](docs/trust/verify-release.md)\n\n## Built-in controls\n\nStave ships 43 S3 controls across 15 categories:\n\n| Category | Controls | What they detect |\n|----------|:---:|-----------------|\n| `public` | 13 | Public read, write, list via policy, ACL, website hosting, prefix exposure |\n| `acl` | 3 | ACL escalation (WRITE_ACP), reconnaissance (READ_ACP), FULL_CONTROL grants |\n| `access` | 5 | Cross-account access, wildcard actions, external write, authenticated-users access |\n| `encrypt` | 4 | Missing encryption at rest, in transit, KMS requirements for PHI |\n| `versioning` | 2 | Disabled versioning, missing MFA delete on backups |\n| `lock` | 3 | Missing object lock, wrong mode, insufficient retention for PHI |\n| `logging` | 1 | Disabled access logging |\n| `lifecycle` | 2 | Missing lifecycle rules, PHI retention below HIPAA minimum |\n| `network` | 1 | Public-principal policies without IP/VPC conditions |\n| `governance` | 1 | Missing data-classification tag |\n| `write_scope` | 2 | Prefix-wide uploads, unrestricted content types |\n| `tenant` | 1 | Missing prefix-based tenant isolation |\n| `takeover` | 2 | Dangling bucket references, dangling CDN origins |\n| `artifacts` | 1 | VCS artifacts exposed on public buckets |\n| `misc` | 2 | Incomplete data preventing safety proof, completeness checks |\n\nFull control reference: [docs/controls/authoring.md](docs/controls/authoring.md)\n\n## CLI commands\n\n| Command | Purpose |\n|---------|---------|\n| `demo` | First finding in 60 seconds |\n| `quickstart` | Auto-detect snapshots and evaluate |\n| `status` | Project state and next steps |\n| `doctor` | Environment readiness check |\n| `init` | Project scaffolding |\n| `validate` | Input correctness |\n| `plan` | Readiness gate |\n| `apply` | Evaluate controls, produce findings |\n| `diagnose` | Explain unexpected results |\n| `trace` | Clause-level predicate detail |\n| `ingest` | Convert AWS snapshots to observations |\n| `controls list` | List available controls |\n| `explain` | Show fields a control requires |\n| `lint` | Control quality checks |\n| `snapshot upcoming` | Next snapshot schedule |\n| `snapshot prune` | Bounded snapshot retention |\n| `snapshot diff` | Drift triage between snapshots |\n| `ci baseline` | Save finding baseline |\n| `ci gate` | Fail CI on new violations |\n| `ci fix-loop` | Verify remediation in CI |\n\n```\nvalidate → plan → apply → diagnose\n   ↓         ↓       ↓        ↓\n Inputs    Ready?  Findings  Insights\n  OK?               Found?    Why?\n                                ↓\n                              trace\n                           (clause detail)\n```\n\n## Concepts\n\n| Term | Definition |\n|------|------------|\n| **Snapshot** | Point-in-time observation of infrastructure assets (JSON) |\n| **Asset** | A single infrastructure component (e.g., S3 bucket) with properties |\n| **Control** | A safety rule assets must satisfy (YAML, `ctrl.v1` schema) |\n| **Unsafe predicate** | Conditions that mark an asset as unsafe |\n| **Finding** | A detected violation with evidence and remediation guidance |\n| **Episode** | A contiguous period where an asset remained unsafe |\n| **Max unsafe duration** | Maximum time an asset may remain unsafe before violation |\n\n## Data formats\n\n| Format | Schema | Purpose |\n|--------|--------|---------|\n| Observations | `obs.v0.1` | Normalized snapshots — flat JSON, one file per timestamp |\n| Controls | `ctrl.v1` | Safety rules — YAML with `unsafe_predicate` |\n| Output | `out.v0.1` | Findings — JSON with `summary` and `findings` array |\n\nSchema references: [ctrl.v1](docs/schema/ctrl.v1.md) | [obs.v0.1](docs/schema/obs.v0.1.md) | [out.v0.1](docs/schema/out.v0.1.md)\n\n## Status\n\n**v0.0.2**\n\n- AWS S3 only\n- Configuration snapshots only\n- Offline evaluation\n\n### Schema stability\n\n| Schema | Version | Status |\n|--------|---------|--------|\n| Observations | `obs.v0.1` | Stable |\n| Controls | `ctrl.v1` | Stable |\n| Output | `out.v0.1` | Stable |\n\n### Exit codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | Success |\n| 2 | Input error |\n| 3 | Violations found |\n| 4 | Internal error |\n| 130 | SIGINT |\n\n## Documentation\n\n- [Start here](docs/start-here.md)\n- [Time to first finding](docs/time-to-first-finding.md)\n- [Design philosophy](docs/design-philosophy.md)\n- [System Invariant as Code](docs/system-invariant-as-code.md)\n- [Evaluation semantics](docs/evaluation-semantics.md)\n- [Authoring controls](docs/controls/authoring.md)\n- [User documentation](docs/user-docs.md)\n- [Architecture overview](docs/architecture/overview.md)\n- [Full docs index](docs/index.md)\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for setup, development workflow, and PR guidelines.\n\n- [Bug reproduction guide](docs/contrib/bug-repro-guide.md)\n- [Bug template](docs/bug-template.md)\n- [CLI style guide](docs/cli-style-guide.md)\n\n## License\n\n[Apache License 2.0](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsufield%2Fstave","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsufield%2Fstave","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsufield%2Fstave/lists"}