From 5cd3f0ba69f27f3e9980cd9956a69c9c3374c040 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:01:30 +0100 Subject: [PATCH] rules(license): cap licence findings at :review strategy (neurophone#99 closeout) Owner directive 2026-06-02 forbids automated licence/SPDX edits. Licence findings are flag-only; downstream pipelines must never auto-execute. Triggered by neurophone#99 (auto-PR reverting PMPL -> MPL-2.0 across ~140 files, closed by owner). - lib/rules/cicd_rules.ex: prepend "POLICY -- Manual Only" header to the License Validation section quoting the verbatim owner directive + 5-way classification. Add `license_finding_strategy/0` (always `:review`), `license_finding_severity_cap/1` (always `:warn`), `license_related_finding?/1` (matches the same regex as the gitbot-fleet dispatcher gate), and `owner_license_classification/0` returning the canonical 5-way map. - lib/scorecard_ingestor.ex: SC-010 `License` -> `auto_fixable: false` with remediation text spelling out the 5-way classification. Canonical: ~/.claude/projects/.../feedback_estate_license_policy_umbrella.md Sibling: ~/.claude/projects/.../feedback_no_automated_licence_edits.md Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/rules/cicd_rules.ex | 91 +++++++++++++++++++++++++++++++++++++++ lib/scorecard_ingestor.ex | 13 +++++- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/lib/rules/cicd_rules.ex b/lib/rules/cicd_rules.ex index 5f37f2fe..20202618 100644 --- a/lib/rules/cicd_rules.ex +++ b/lib/rules/cicd_rules.ex @@ -1306,6 +1306,40 @@ defmodule Hypatia.Rules.CicdRules do # --------------------------------------------------------------------------- # License Validation # --------------------------------------------------------------------------- + # + # POLICY — Manual Only (owner directive 2026-06-02; triggered by neurophone#99) + # ---------------------------------------------------------------------------- + # Findings emitted by this section are **report-only / review-strategy**. + # They MUST NEVER reach `:auto_execute` confidence, regardless of how + # cleanly the SPDX validator fires. Licence / SPDX remediation is + # manual, per-file, owner-only. Every prior LLM-driven sweep has + # scrambled headers, mis-licensed third-party code, or reverted owner + # decisions (see neurophone#99 closed 2026-06-02). + # + # Five-way classification (verbatim owner directive 2026-06-02): + # "mpl-2.0 is for my sole repos, all rights reserved is for 007, + # agpl-3.0-or-later is for those shared with my son, and leave other + # people's forked stuff alone … only palimpsest license for obvious + # reasons should be talking about palipsest and palimpsest plasma, + # and consent-aware-http, but in that case prospectively" + # + # 1. Sole owner repos (default) → MPL-2.0 + # 2. The 007 repo → All Rights Reserved (out-of-scope) + # 3. Shared with son → AGPL-3.0-or-later (idaptik, paint-type, …) + # 4. Third-party / forks → leave alone, flag-only + # 5. Palimpsest carve-out → PMPL-1.0-or-later for EXACTLY + # palimpsest-license, palimpsest-plasma, + # and consent-aware-http (prospective) + # + # Canonical memory files: + # ~/.claude/projects/.../feedback_estate_license_policy_umbrella.md + # ~/.claude/projects/.../feedback_no_automated_licence_edits.md + # + # Downstream consumers (recipe-generator, dispatch-runner) MUST treat + # any licence-category finding as `auto_fixable: false` / strategy + # `:review`. The `license_finding_severity_cap/1` and + # `license_finding_strategy/0` functions below encode that cap. + # ---------------------------------------------------------------------------- @required_spdx "MPL-2.0" # `MPL-2.0` is intentionally absent here — it's the required identifier @@ -1367,6 +1401,63 @@ defmodule Hypatia.Rules.CicdRules do def license_exception_paths_for(_), do: [] + # --------------------------------------------------------------------------- + # License-finding strategy cap (owner directive 2026-06-02) + # --------------------------------------------------------------------------- + # + # License/SPDX findings MUST NEVER drive auto-execute fixes. These helpers + # are the canonical cap consulted by downstream pipelines (recipe-generator, + # dispatch-runner). Do not bypass. + + @doc """ + Strategy for any licence-related finding. Always `:review` (never + `:auto_execute`). Owner must approve and apply licence edits manually. + """ + def license_finding_strategy, do: :review + + @doc """ + Maximum severity any licence-related finding may carry. Capped at `:warn` + so the dispatcher never escalates to auto-execute confidence. + """ + def license_finding_severity_cap(_severity), do: :warn + + @doc """ + Returns true if a finding category / recipe / pattern id is licence-related + and therefore subject to the auto-fix refusal gate. Mirrors the regex used + in `gitbot-fleet/scripts/dispatch-runner.sh`. + """ + def license_related_finding?(category_or_recipe) when is_binary(category_or_recipe) do + lower = String.downcase(category_or_recipe) + + String.contains?(lower, "license") or + String.contains?(lower, "spdx") or + String.contains?(lower, "pmpl") or + String.contains?(lower, "mpl-2") or + String.contains?(lower, "agpl") or + String.contains?(lower, "palimpsest") + end + + def license_related_finding?(_), do: false + + @doc """ + Five-way licence classification per owner directive 2026-06-02. Returned + as a map for downstream tooling that needs to render policy in error + messages or PR descriptions. + """ + def owner_license_classification do + %{ + sole_owner_repos: "MPL-2.0", + "007": "All Rights Reserved", + shared_with_son: "AGPL-3.0-or-later", + third_party_forks: :leave_alone, + palimpsest_carve_out: %{ + license: "PMPL-1.0-or-later", + repos: ["palimpsest-license", "palimpsest-plasma", "consent-aware-http"], + note: "consent-aware-http is prospective only — do NOT retroactively flip" + } + } + end + @doc """ Validate a license SPDX identifier, optionally scoped to a repo name. AGPL-3.0-or-later is permitted for repos in @agpl_exception_repos. diff --git a/lib/scorecard_ingestor.ex b/lib/scorecard_ingestor.ex index 5cc2768b..5731cb78 100644 --- a/lib/scorecard_ingestor.ex +++ b/lib/scorecard_ingestor.ex @@ -101,10 +101,19 @@ defmodule Hypatia.ScorecardIngestor do remediation: "Integrate with OSS-Fuzz or add language-specific fuzzing." }, "License" => %{ - id: "SC-010", pa_rule: "SC010", risk: :low, auto_fixable: true, + # `auto_fixable: false` per owner directive 2026-06-02 (triggered by + # neurophone#99). Licence/SPDX edits are manual, per-file, owner-only. + # See `feedback_no_automated_licence_edits.md` and + # `feedback_estate_license_policy_umbrella.md`. SPDX choice is owner- + # specific (5-way classification) and cannot be auto-derived. + id: "SC-010", pa_rule: "SC010", risk: :low, auto_fixable: false, category: "LicenseCompliance", description: "No license file found", - remediation: "Add LICENSE file with SPDX identifier to repository root." + remediation: + "Owner must manually add LICENSE file. SPDX choice depends on owner classification " <> + "(sole repo → MPL-2.0; 007 → ARR; son-shared → AGPL-3.0-or-later; " <> + "fork → leave alone; palimpsest carve-out → PMPL-1.0-or-later). " <> + "Do NOT auto-generate." }, "Maintained" => %{ id: "SC-011", pa_rule: "SC011", risk: :high, auto_fixable: false,