Repository navigation
fix(root_hygiene): accept LICENSE.adoc / LICENSE.md and a REUSE LICENSES/ dir - #963
Conversation
…SES/ dir The licence requirement accepted only `LICENSE` and `LICENSE.txt`. The estate template ships `LICENSE.adoc` plus a REUSE `LICENSES/` directory, so the template and every repo synced from it got a critical "Required file missing" finding that fails the zero-critical gate. Accept `LICENSE.md` and `LICENSE.adoc` as alternatives, and in `scan/2` (where the repo path is known) accept a `LICENSES/` directory that holds at least one file. Root file lists carry no directories, so the filename-only `scan/1` cannot see `LICENSES/` and is unchanged there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 37 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 28138025c0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # `LICENSES/`), so the AsciiDoc and Markdown spellings count too. | ||
| %{ | ||
| file: "LICENSE", | ||
| alternatives: ["LICENSE.txt", "LICENSE.md", "LICENSE.adoc"], |
There was a problem hiding this comment.
Update the default scorecard scan for LICENSE.adoc
When a repository relies on the newly accepted LICENSE.adoc, a default CLI scan still runs the :scorecard module and Hypatia.ScorecardIngestor.check_license/2, whose candidate list omits this spelling, so the same invocation reports SC-010 "No LICENSE file found" even though root hygiene now accepts it. Add LICENSE.adoc to that checker as part of introducing the new accepted name so the default product does not return contradictory license results.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid. This PR had already merged, so the fix is in #970. SC-010 now accepts LICENSE.adoc and calls root hygiene's REUSE check (RootHygiene.reuse_licenses?/1, now public), so the two checks can't disagree.
Generated by Claude Code
|
Add Carrot credits or activate Agent usage billing to use Autofix |
The REUSE branch accepted a LICENSES/ directory holding any regular file, so a repo with no licence but a stray `.gitkeep` or README there passed. The REUSE spec requires non-empty licence texts named `<SPDX-ID>.<ext>`. Count only non-empty, non-hidden files with an extension, and not READMEs. This matches the same tightening in rsr-template-repo's licence checks (rsr-template-repo#258, 9b0ceeb). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F
…enSSF check (#258) ## Summary This PR fixes two problems in the estate template's CI. 1. **Hypatia's GitHub-API rules got no token.** Hypatia's scan step ran without credentials, so its rules that query the GitHub API quietly returned nothing in every repo synced from this template. When hyperpolymath/echo-types re-synced to this workflow (hyperpolymath/echo-types#354), its finding count fell from 38 to 3, mostly for this reason. 2. **The licence checks rejected `LICENSE.adoc`.** That's the file this template ships, so the checks were red on the template and in every repo minted from it. ## Changes **`hypatia-scan.yml`** - **Token:** pass `GITHUB_TOKEN: ${{ github.token }}` to the scan step only, not the whole job. It's `github.token` rather than `secrets.GITHUB_TOKEN`, so the scan doesn't raise its own harden-runner finding (RE001). - **Permissions:** grant `vulnerability-alerts: read`, which Hypatia's Dependabot-alert rules need. `security-events` only covers code-scanning alerts. The key is valid in GitHub's workflow schema (SchemaStore): the edited workflow passes, and a made-up key fails. - **Cache key:** the key now reads `${{ env.HYPATIA_SHA }}` instead of repeating the SHA. Before, bumping the pin without also editing the key would reuse the old scanner build. **Licence checks** (`ossf-best-practices.yml`, and `just verify` / `self-assess` in `build/just/assess.just`) - They now accept `LICENSE`, `LICENSE.txt`, `LICENSE.md` or `LICENSE.adoc`. - They also accept a REUSE `LICENSES/` directory, but only if it holds a non-empty, non-hidden `<SPDX-ID>.<ext>` licence text (not a README). - `just verify` runs inside `just repo-init`, so its old `LICENSE`-only check failed every mint. That's the Proven suite's template-mint E2E lane. - No licence file is changed. ## What the token can and can't reach - **Code-scanning alerts:** reachable, through `security-events`. - **Dependabot alerts:** reachable, through `vulnerability-alerts: read`, which this PR adds. - **Secret-scanning alerts:** not reachable. No `GITHUB_TOKEN` permission covers them; they need a GitHub App or PAT. That's an owner decision (it would add a secret to the template), so it's left out. - **Branch protection:** may be refused for the job token. - **When a call is refused:** the rule logs a warning and returns `[]`, so a refusal costs coverage but never produces a false finding. BH001 ("no protection at all") fires only on a genuine "Branch not protected" answer. ## Evidence from CI Compared with `main` (`0d3fcfe`), the Hypatia Security Scan on this PR: - **no longer logs the three "GITHUB_TOKEN not set" warnings.** That shows the alert queries ran with a token. It doesn't show they all succeeded; see the section above. - **reports 30 findings instead of 5.** - **restored the same cache entry**, because the new key resolves to the same string. OpenSSF Compliance is now green. ## Still red, and why Details are in [this comment](#258 (comment)). - **Hypatia critical finding (missing `LICENSE`):** waits on hyperpolymath/hypatia#963. Once it merges, I'll bump `HYPATIA_SHA` here and in the two other workflows that pin the same SHA. That bump also brings in hyperpolymath/hypatia#960, which clears the old `0-AI-MANIFEST` high finding. - **estate-rules, Central Estate CI/CD Audit, and the `root_shape` benchmark:** fixed by #260. ## Testing - **Licence checks:** run against seven layouts, and all three checks agree on each. - Pass: `LICENSE.adoc`, and `LICENSES/MPL-2.0.txt`. - Fail: `.gitkeep` only, README only, an empty licence file, a dotfile only, and no licence at all. - **`just verify` on this tree:** the old recipe exits 1 with the CI message; the new one exits 0. - **shellcheck 0.9.0:** clean. - **SchemaStore workflow schema:** both edited workflows validate. ## RSR Quality Checklist ### Required - [x] No banned language patterns - [x] SPDX license headers present on all modified files (unchanged) - [x] No secrets, credentials, or `.env` files included. The scan uses the job token, not a secret. - [x] Linter is clean (Workflow Security Linter green) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F --------- Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
#261) ## Summary The template pins Hypatia at `d73f76b`. That version predates two fixes: - hyperpolymath/hypatia#960: accepts the repo deed `<repo>_chora.deed` as the AI manifest. - hyperpolymath/hypatia#963: accepts `LICENSE.adoc` and REUSE `LICENSES/` as the licence. Under the old pin the template raised a **critical** "Required file missing: LICENSE" and a **high** `0-AI-MANIFEST` finding, so the zero-critical gate in the Hypatia Security Scan and the Static Analysis Gate failed. This was the bump promised in #258. ## Changes - The pin moves from `d73f76b` to Hypatia `main` at `7c10e5d`, which includes #960, #963 and #969. - It's updated in all three workflows that carry it, so they stay on one version: `hypatia-scan.yml` (`HYPATIA_SHA`), `static-analysis-gate.yml` and `dogfood-gate.yml`. - `hypatia-scan.yml`'s cache key reads `HYPATIA_SHA` since #258, so it follows on its own. - The other two have the SHA in their cache keys, and those are updated in place. ## Testing - **Root hygiene at `7c10e5d`:** I ran the rule against this repo's root and it returns **no findings**. At `d73f76b` it returned the critical and the high. - **Schema:** all three workflows validate against the GitHub workflow schema (SchemaStore). - **Old pin:** no copy of the old SHA remains in the tree. `actions.lock` is unaffected, because this SHA is a git ref, not an action pin. - **Full scan:** I couldn't build the full scanner locally because Hex is unreachable. This PR's Hypatia Security Scan and Static Analysis Gate runs are the end-to-end check. ## Follow-up hyperpolymath/hypatia#970 (open) makes SC-010, a Low-severity finding that doesn't block, accept `LICENSE.adoc`. It also adds pagination and a timeout to the secret-scanning sweep. Once it merges, a second small bump picks it up. --- _Generated by [Claude Code](https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F)_ Co-authored-by: Claude <noreply@anthropic.com>
…pe, 7c10e5d (Hypatia findings, part 2) (#356) ## Summary Part 2 of fixing the Hypatia findings on echo-types. Part 1 (#354) took the template's `hypatia-scan.yml` as it stood then. That version silently dropped every API-backed rule, because it passed the scanner no token. The fix went into the template first (hyperpolymath/rsr-template-repo#258 and #261). This PR takes the merged result, byte-identical. | Change | Why | |---|---| | The scan step gets `GITHUB_TOKEN: ${{ github.token }}`, scoped to that step | Hypatia's code-scanning, Dependabot, branch-protection and baseline-health rules return `[]` without a token. It is `github.token`, not `secrets.*`, so RE001 stays clear. | | `vulnerability-alerts: read` on the job | Lets the Dependabot (DA) rules read alerts. `security-events: write` covers only code scanning. | | `HYPATIA_SHA` `d73f76b` → `7c10e5d` | This scanner accepts `LICENSE.adoc` and REUSE `LICENSES/` (hyperpolymath/hypatia#963). It no longer demands `0-AI-MANIFEST.a2ml` (hyperpolymath/hypatia#960). | | Cache key `…-${{ env.HYPATIA_SHA }}` | A pin bump now rebuilds the scanner. Before, it reused the old build under a hard-coded key. | | `upload-sarif` moves to codeql-action v4.39.1 (`9b32540`) | Matches the template. | `actions.lock` is updated to match. `hypatia-scan.yml` now lists codeql-action at `9b32540`, and that pin has its dependency entry. The v4.38.0 entry stays, because the `metadatastician/standards` reusable workflows still pin it. ## What this does not cover - **Secret-scanning alerts.** No `GITHUB_TOKEN` permission can read them, so the per-repo scan never sees them. The workflow comment says so. They will come from a separate, private estate-wide sweep with a dedicated read-only token, not from this repository. - **The finding count will go up.** The API-backed rules are scanning again, so expect findings that were unscanned under #354, not new problems. ## Verification - `hypatia-scan.yml` is `cmp`-identical to `rsr-template-repo@4f4536e`. That file passed GitHub-workflow schema validation and the template's CI in #258 and #261. - `actions.lock` parses, and its `hypatia-scan.yml` list now names exactly the four pins the workflow uses. - I could not run `gh actions-lock` here. The lock edit mirrors the format that tool writes, and this PR's CI run is the check that matters. --- _Generated by [Claude Code](https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F)_ Co-authored-by: Claude <noreply@anthropic.com>
…LICENSE.adoc (#970) ## Summary This fixes three defects from #963 and #969. Codex flagged them after those PRs had already merged. It also tightens the REUSE licence rule after CodeRabbit's review here. ## Changes `lib/rules/secret_scanning_alerts.ex` (from #969) - **Pagination:** the fetch read only the first page of 100 alerts, so `sweep/2` returned `status: ok` with older open, stale or badly dismissed alerts missing. It now follows GitHub's `Link: rel="next"` header until the last page. - It only follows links on `api.github.com`, because the token goes with every request. - Past 50 pages (5,000 alerts) it returns an error rather than a truncated list. - **Timeout:** the curl call had no deadline, so one stalled repository could hang an estate-wide sweep. Each request now has `--max-time 30`, and a timeout (curl exit 28) is reported as `GitHub API request timed out after 30s`. - **Header parsing:** responses are read with `curl -i` so the `Link` header is available. If an HTTPS proxy adds its own "Connection established" header block first, it's skipped. `lib/scorecard_ingestor.ex` and `lib/rules/root_hygiene.ex` (from #963) - **SC-010 now agrees with root hygiene.** The local Scorecard licence check still rejected `LICENSE.adoc` and REUSE `LICENSES/`, so a single scan reported both "licence present" (root hygiene) and "No LICENSE file found" (SC-010). It now accepts `LICENSE.adoc` and calls root hygiene's REUSE check. - **`RootHygiene.reuse_licenses?/1` is now public.** The REUSE rule has one definition instead of two copies that could drift apart. REUSE strictness (e5f5a7a, owner decision on CodeRabbit's finding) - **The problem:** a `LICENSES/` file used to count if it was any non-empty `<name>.<ext>`. So `LICENSES/notes.txt` alone passed both licence checks. - **The fix:** its stem must now be on the SPDX License List or be a REUSE `LicenseRef-` id. Matching is exact. - **Why a list, not a filename rule:** real identifiers such as `curl` and `blessing` are lowercase, so no heuristic separates them from `notes`. The list is vendored instead: - `priv/spdx/license-ids.txt` holds SPDX License List 3.29.0: 740 identifiers, deprecated ones included. Its header records the source tag. - `scripts/refresh-spdx-license-ids.sh <tag>` regenerates the file and refuses a suspiciously short download. - `Hypatia.SPDX` reads the file at compile time, so the escript needs no `priv/` at run time. - **Owner action:** the vendored list is third-party data. I have not added a `.reuse/dep5` entry for it, because licence records are yours to make. ## Testing Run with plain Elixir 1.14 and a local JSON stand-in, as for #969. Hex isn't reachable from here, and CI's `mix test` uses the real Jason. - **Overall:** 84 of 84 pass across `secret_scanning_alerts_test.exs`, `root_hygiene_test.exs`, `scorecard_ingestor_license_test.exs`, `scorecard_ingestor_security_policy_test.exs` (regression guard) and the new `spdx_test.exs`. - **Behaviour tests fail on the old code.** The 10 tests from the first commit fail against `main`. The two `notes.txt` tests fail against the previous `reuse_licenses?/1`. - `parse_page/1`: the next link, the last page, the proxy header block, and an error page. - `collect_pages/2`: two pages joined, a next link to another host refused, a failed later page failing the whole fetch, the page cap raising an error, and exactly 50 requests before the cap. - SC-010: `LICENSE.adoc`, REUSE and `LicenseRef-` pass. A `.gitkeep`-only `LICENSES/` and a `notes.txt` fail. - `Hypatia.SPDX`: listed, lowercase, deprecated and `LicenseRef-` ids count; other names and case variants do not. - **Formatting:** `mix format --check-formatted` passes on every changed file. `shellcheck` passes on the refresh script. --- _Generated by [Claude Code](https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F)_
Summary
root_hygieneonly countsLICENSEorLICENSE.txtas the repo's licence file. The estate templatersr-template-reposhipsLICENSE.adocand a REUSELICENSES/directory. So the template, and every repo synced from it, gets a critical "Required file missing" finding, which fails the template's zero-critical Hypatia gate. hyperpolymath/rsr-template-repo#258 shows this, and so does that repo'smain.Change
lib/rules/root_hygiene.ex, inscan_required_missing:LICENSE.mdandLICENSE.adocnow satisfy the requirement, alongsideLICENSEandLICENSE.txt.LICENSES/directory:scan/2(the CLI path) also accepts aLICENSES/directory, as long as it holds at least one REUSE licence text.<SPDX-ID>.<ext>file that isn't a README, as the REUSE spec requires.LICENSES/, or one holding only.gitkeep, a README, an empty file or an extensionless file, declares nothing and still produces the finding.scan/1can't see the directory, becauselist_root_filesdrops directories. It behaves as before.Testing
Mix deps can't be fetched in this environment. As with #960, I compiled the module standalone and ran
test/root_hygiene_test.exswith plain Elixir..adocand.md, rejectLICENSE.adoc.orig, check the REUSE directory both empty and with a licence in it, and reject non-licence files inLICENSES/.main.mix format --check-formattedpasses.The full
mix testruns in CI.🤖 Generated with Claude Code
https://claude.ai/code/session_01P4yFkxW5Heb8p2YW7ZYs9F