Skip to content

fix(security): SafeConstructor for SnakeYAML + CORS hardening#4

Merged
aksOps merged 2 commits intomainfrom
fix/snakeyaml-safeconstructor-cors
Mar 31, 2026
Merged

fix(security): SafeConstructor for SnakeYAML + CORS hardening#4
aksOps merged 2 commits intomainfrom
fix/snakeyaml-safeconstructor-cors

Conversation

@aksOps
Copy link
Copy Markdown
Contributor

@aksOps aksOps commented Mar 31, 2026

Summary

  • Replace all new Yaml() with new Yaml(new SafeConstructor(new LoaderOptions())) to prevent arbitrary Java class instantiation via YAML tags (CVE-class deserialization vulnerability)
  • Harden CORS configuration: replace wildcard allowedOrigins("*") with configurable allowedOriginPatterns defaulting to localhost only
  • Add 21 new tests covering CORS configuration and ProjectConfigLoader overrides including unsafe YAML tag rejection

Files Changed

Security fixes:

  • ProjectConfigLoader.java — 2 locations
  • ConfigScanner.java — 2 locations
  • StructuredParser.java — 1 location
  • GraphCommand.java — 1 location (output-only, hardened for consistency)
  • CorsConfig.java — configurable origin patterns

Tests added:

  • CorsConfigTest.java — 7 tests
  • ProjectConfigLoaderApplyOverridesTest.java — 14 tests

Test plan

  • All 21 new tests pass
  • Full test suite passes (1432 tests, 0 failures)
  • Unsafe YAML tags rejected by SafeConstructor
  • CORS restricted to localhost patterns by default

🤖 Generated with Claude Code

aksOps and others added 2 commits March 31, 2026 17:28
…den CORS

SnakeYAML's default constructor allows arbitrary Java class instantiation
via YAML tags (e.g. !!javax.script.ScriptEngineManager). Replace all
instances of new Yaml() used for loading with
new Yaml(new SafeConstructor(new LoaderOptions())) in:
- ProjectConfigLoader (2 locations)
- ConfigScanner (2 locations)
- StructuredParser (1 location)
- GraphCommand (1 location, output-only but hardened for consistency)

CORS: Replace wildcard allowedOrigins("*") with configurable
allowedOriginPatterns defaulting to localhost. Configurable via
codeiq.cors.allowed-origin-patterns property.

Includes 21 new tests: 7 CorsConfig tests + 14 ProjectConfigLoader tests
covering override paths, unsafe YAML tags, and parser settings.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

@aksOps aksOps merged commit f046489 into main Mar 31, 2026
10 checks passed
@aksOps aksOps deleted the fix/snakeyaml-safeconstructor-cors branch April 3, 2026 15:58
aksOps added a commit that referenced this pull request Apr 25, 2026
…SSoT (RAN-46)

The codeql.yml workflow added in 638fda7 conflicts with the repo-level
CodeQL default setup that was already enabled for `java-kotlin`,
`javascript-typescript`, and `actions`. GitHub Code-Scanning rejects
duplicate SARIF uploads for the same language with a "configuration error"
(see PR #74's failed `Analyze (javascript-typescript)` run 24928083508).

Default setup already covers everything the workflow added (multi-language
analysis, SARIF in the Security tab, push + PR + scheduled runs) and is a
managed GitHub feature that auto-updates. Keeping the workflow buys us
nothing here and breaks every PR with a stuck failed check.

Adjustments:
  - delete .github/workflows/codeql.yml
  - .bestpractices.json: point `code_scanning` evidence at the default-setup
    repo setting instead of the deleted workflow
  - engineering-standards.md §9: document the decision and why default setup
    won

Refs RAN-46 AC #4. Default-setup is being kept enabled per @ceo's post-merge
sequence (item #3).
aksOps added a commit that referenced this pull request Apr 25, 2026
…penSSF wiring) (#74)

* chore(bootstrap): RAN-46 engineering bootstrap (security, runbooks, OpenSSF wiring)

Lands the static side of the one-shot RAN-46 bootstrap. No code or build
changes — only governance + supply-chain artifacts the rest of the AC list
depends on.

Adds:
  - shared/runbooks/{release,rollback,first-time-setup,engineering-standards}.md
    (release.md is the gate referenced by the CEO bootstrap precondition for
     every downstream RAN-* product issue)
  - SECURITY.md  (private-disclosure contact, supported versions, scope)
  - AGENTS.md    (repo-root entry point pointing at CLAUDE.md and runbooks)
  - .bestpractices.json (OpenSSF Best Practices self-assessment skeleton —
                         project_id pending board registration per AC #8)
  - .github/dependabot.yml (Maven + GHA + npm, weekly grouped)
  - .github/workflows/codeql.yml + scorecard.yml (every action pinned by
                                                  commit SHA per Scorecard
                                                  Pinned-Dependencies)
  - scripts/setup-git-signed.sh (idempotent repo-local ssh-signing config)
  - README.md badge row: OpenSSF Scorecard + Best Practices placeholder
  - LICENSE: copyright "Amit Kumar" per AC #6

Verified locally:
  - git config --local user.signingkey resolves to ~/.ssh/id_ed25519.pub
  - git commit-tree -S succeeds and verify-commit reports a valid SSH sig
  - All GitHub Actions in new workflows pinned by 40-char commit SHA

Out of this slice (follow-up commits/PRs on this same branch):
  - jacoco 85% rule + dependency-check failBuildOnCVSS=7 in pom.xml
  - SHA-pinning of existing ci-java.yml / beta-java.yml / release-java.yml
  - Branch protection + Dependabot security-updates + private vuln reporting
    (driven post-merge via gh api — recorded as RAN-46 comments)
  - Hello-world deploy proof (blocked on AC #10 scope decision from @coo)
  - paperclip Project codebase.repoUrl PATCH (final step after this PR merges)

Refs RAN-46.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(bootstrap): RAN-46 wire 85% jacoco gate, dep-check CVSS>=7, SHA-pin remaining actions

Closes the dynamic side of the Slice A bootstrap (the static governance
artifacts landed in 638fda7). All AC #5 / Scorecard Pinned-Dependencies
items now satisfied on the branch:

  - pom.xml jacoco-maven-plugin: re-enable the `check` execution (bound
    to `verify` phase) with BUNDLE LINE COVEREDRATIO >= 0.85.
    Fails `mvn verify` below threshold, per AC #5 (gate is not just
    Sonar — explicit jacoco rule required).
  - pom.xml dependency-check-maven: add `failBuildOnCVSS=7` so any
    High/Critical CVE in transitive deps fails the build, per
    rules/security.md ("High/Critical = block").
  - ci-java.yml / beta-java.yml / release-java.yml: pin
    actions/checkout, actions/setup-java, actions/upload-artifact, and
    softprops/action-gh-release to 40-char commit SHAs (with version
    comments) so OSSF Scorecard `Pinned-Dependencies` passes for the
    whole repo, not just the new workflows.

SHAs:
  - actions/checkout@de0fac2e (v4.2.2)
  - actions/setup-java@be666c2f (v4.7.1)
  - actions/upload-artifact@043fb46d (v4.6.2)
  - softprops/action-gh-release@3bb12739 (v2)

Refs RAN-46.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(bootstrap): drop workflow-driven CodeQL — default setup is the SSoT (RAN-46)

The codeql.yml workflow added in 638fda7 conflicts with the repo-level
CodeQL default setup that was already enabled for `java-kotlin`,
`javascript-typescript`, and `actions`. GitHub Code-Scanning rejects
duplicate SARIF uploads for the same language with a "configuration error"
(see PR #74's failed `Analyze (javascript-typescript)` run 24928083508).

Default setup already covers everything the workflow added (multi-language
analysis, SARIF in the Security tab, push + PR + scheduled runs) and is a
managed GitHub feature that auto-updates. Keeping the workflow buys us
nothing here and breaks every PR with a stuck failed check.

Adjustments:
  - delete .github/workflows/codeql.yml
  - .bestpractices.json: point `code_scanning` evidence at the default-setup
    repo setting instead of the deleted workflow
  - engineering-standards.md §9: document the decision and why default setup
    won

Refs RAN-46 AC #4. Default-setup is being kept enabled per @ceo's post-merge
sequence (item #3).

* docs(bootstrap): record CEO ruling on RAN-46 AC #10 — deploy = Maven Central + GH Releases

Per @ceo comment fd1160d2 on RAN-46:

- engineering-standards.md §7.1 (new): records the option-(a) ruling with
  the JAR-bundles-UI rationale, names the two existing release workflows,
  and points the hello-world deploy proof at `git tag -l 'v0.0.1-beta.*'`
  + `gh release list` (47+ beta tags, 46+ GH pre-releases on file).
- release.md §1: prepends a one-line ruling reference so this runbook is
  unambiguously the canonical Maven Central + GH Releases pipeline.
- CLAUDE.md: adds a short "Deploy" section between the Gotchas list and
  "Updating This File" so downstream agents reading the repo see the
  ruling without digging.

Closes RAN-46 AC #10. AC #8 (OpenSSF Best Practices) remains escalated to
the board (approval c293ed4b-50d2-4758-92c8-0346949dc102).

* fix(bootstrap): address Reviewer findings on PR #74 (RAN-47)

All 8 review findings on the bootstrap PR addressed in one commit on the
same branch — squash-merge stays clean.

Findings → fixes:

1. pom.xml: dependency-check:check was configured (failBuildOnCVSS=7) but
   not bound to a Maven phase, so `mvn verify` never ran the gate.
   Added an `<execution>` binding `check` to `verify` (RAN-46 AC #5).

2. shared/runbooks/release.md §3: the runbook said "push v* tag → workflow
   runs", but `release-java.yml` is `workflow_dispatch` only and the
   workflow itself creates and pushes the tag. Rewrote §3 to use
   `gh workflow run release-java.yml -f version=X.Y.Z` and to describe the
   actual deploy → tag → GH Release order. Direct tag-push without the
   workflow does not publish.

3. scripts/setup-git-signed.sh: removed the hard-coded "Amit Kumar" /
   "ak.nitrr13@gmail.com" defaults. Identity now resolves from env vars,
   then `git config --global` (user.name / user.email / user.signingkey),
   and the script errors out (rc=4) with a clear remediation message if
   neither is set. No more silent maintainer-misattribution.

4. shared/runbooks/first-time-setup.md §2: replaced the invalid
   `git verify-commit --raw -` (which expects a commit id, not stdin) with
   a working two-step pattern that captures the signed object and verifies
   it via `git verify-commit "$sig_commit"` + `git log -1 --pretty=%G?`.

5. shared/runbooks/first-time-setup.md §3 quick-loop: dropped the
   contradictory `-DskipTests test` (which skipped every test). Now uses
   `-Dspotbugs.skip=true -Ddependency-check.skip=true` to keep the inner
   loop fast WITHOUT skipping tests, and adds a note explaining the prior
   draft was wrong.

6. shared/runbooks/first-time-setup.md §5: removed Scorecard from the
   "required PR-green check" list — Scorecard runs on push-to-main + weekly
   cron, never on pull_request, and is intentionally non-gating per
   engineering-standards.md §1. Replaced "signed-commits status check"
   with the correct framing (branch-protection rejects unsigned commits,
   not a separate status check).

7. SECURITY.md: replaced the stale `.github/workflows/codeql.yml` link
   (workflow removed in 35762b1) with a description of the repo-level
   CodeQL default setup that supersedes it. Also clarified that the
   workflow-driven codeql.yml was attempted and removed because of the
   default-setup SARIF-upload conflict.

8. shared/runbooks/release.md §2 pre-release checklist: dropped the
   "OSV-Scanner workflow latest run green" line (no such workflow). The
   dependency audit gate is now the bound `mvn verify` from fix #1, with
   a Dependabot security-tab cross-check.

Refs RAN-47 (Reviewer findings comment 5a572640).

* fix(bootstrap): unblock PR #74 build + address RAN-47 release-tag finding

A. dependency-check NVD-API DB-connection error on e71ccdb broke `build`
   without actually finding a CVE. Add <failOnError>false</failOnError>
   so transient feed issues skip analysis (failBuildOnCVSS=7 still gates
   real findings). RAN-42 tracks making the gate fully robust.

B. Reviewer 47b718b9 — release-java.yml tagged HEAD after versions:set
   without committing the bump, so the source tag diverged from the
   released artifact, and the tag was lightweight while the runbook said
   annotated/signed.

   Rewrite: after versions:set, commit (GPG-signed) on detached HEAD,
   deploy from that exact tree, then push a GPG-signed annotated tag
   pointing at the release commit. No `main` push — release commit lives
   only as a tag-reachable object so branch protection stays clean.
   release.md §3 rewritten to match.

Refs RAN-47.

* fix(bootstrap): round-3 reviewer findings on PR #74 (RAN-47)

Four blockers raised on `1dad7e7`:

1. `<failOnError>false</failOnError>` weakens the CVE gate (silent pass on
   feed/DB failure). Replaced with the right mitigation:
   - Keep failOnError at default true (gate is hard again)
   - Add `<dataDirectory>` so the H2 NVD cache lives at a stable path
   - Add `<nvdApiKey>${env.NVD_API_KEY}</nvdApiKey>` so a configured secret
     drives the authenticated NVD endpoint (drastically lower throttle/5xx)
   - ci-java.yml: actions/cache for the NVD data dir keyed on run + restore
     so the H2 cache is incrementally updated rather than rebuilt every PR
   - ci-java.yml: pass `NVD_API_KEY: ${{ secrets.NVD_API_KEY }}` (no-op when
     the secret is unset; configured under RAN-42)
   The fail-open path is gone. CVE findings AND scanner-operational
   failures both red the build.

2. `rollback.md` documented `git revert -m 1 <merge-sha>` for squash
   merges. Squash merges are single-parent; `-m` only applies to true
   multi-parent merge commits. Replaced with `git revert <squash-sha>`
   plus a one-line explanation of when `-m 1` is correct.

3. `CLAUDE.md` Deploy section claimed `release-java.yml` is triggered by
   `vX.Y.Z` tag pushes. Reality (and now the runbook in `release.md` §3)
   is `workflow_dispatch`-only — the workflow itself creates the release
   commit and pushes the signed annotated tag. Updated CLAUDE.md to match.

4. `engineering-standards.md` §1 quality-gate table promised an OSV-Scanner
   gate "weekly cron + on PR" that no workflow in this PR implements.
   Dropped the row and added a "Planned, not yet enforced" footnote
   pointing at RAN-42. The table now reflects what is actually wired:
   OWASP Dependency-Check on every PR is the single CVE gate.

Refs RAN-47.

* fix(bootstrap): R4-1 docs + CPE-collision suppressions (RAN-47)

Reviewer round-4 finding on `fdac5c8` plus CI build-failure analysis:

R4-1 (Reviewer blocker): `shared/runbooks/engineering-standards.md` §7.1
deploy-pipeline table said GA release was triggered by `vX.Y.Z` tag push
while every other doc (release-java.yml, release.md, CLAUDE.md) says
`workflow_dispatch`-only. Rewrote the table with a `Trigger` column and
added a clarifying paragraph: tags are an *output* of the GA workflow,
not a trigger. This eliminates the docs contradiction.

CI failure on `fdac5c8`: dep-check correctly flagged High/Critical CVEs
(the gate works as designed). Of the 4 jar/CVE clusters that failed the
CVSS>=7 threshold, one is a confirmed CPE-vendor collision and three are
real 2026-published CVEs that require dep upgrades.

Added `dependency-check-suppressions.xml` (referenced from pom.xml via
<suppressionFiles>) covering ONLY the CPE-collision false positives:

  1. spring-ai-starter-mcp-server-webmvc 2.0.0-M3 incorrectly matched
     against cpe:2.3:a:vmware:server:2.0.0 (an EOL VMware hypervisor)
     and the non-existent cpe:2.3:a:vmware:spring_ai. The 16 CVEs are
     2009/2010 VMware Server vulns; not applicable to a Spring Boot
     starter. CPE collision only — suppressed with TechLead sign-off.

  2. spring-boot-neo4j 4.0.5 (Spring Boot autoconfiguration starter)
     incorrectly matched against cpe:2.3:a:neo4j:neo4j:4.0.5. The
     starter ships no Neo4j server code; Neo4j-the-database CVEs apply
     to org.neo4j:* artifacts, not to the Spring Boot bridge.

The remaining 3 real CVE clusters (CVE-2026-25087 on Apache Arrow 18.3.0,
CVE-2026-33186 on gRPC 1.78.0, CVE-2026-5795 on Jetty 12.x) are NOT
suppressed. Per security.md §5, High/Critical = fix-immediately, not
document-non-exploitability. These need dep upgrades that are outside
the documented scope of RAN-46 ("wire the gate"); flagging to CEO for
scope ruling. The gate is functioning correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>

* fix(security): document non-exploitability for the 3 real 2026-* CVEs (RAN-47)

Per @ceo Option C ruling: investigate fix-versions for each gate-failing
CVE; defer to RAN-X only if a fix forces a major upgrade. Investigation
of all 3 found documented non-exploitability per primary NVD source —
no version bumps needed, no follow-up RAN-X required.

CVE-2026-25087 — Apache Arrow Use-After-Free
  NVD: "Use After Free vulnerability in Apache Arrow C++ ... The
  functionality is not exposed in language bindings (Python, Ruby,
  C GLib), so these bindings are not vulnerable."
  Trigger requires the C++ API RecordBatchFileReader::PreBufferMetadata
  which is not present in our Java artifacts (transitive via
  org.neo4j:arrow-bom:2026.02.3). Suppressed with NVD-source evidence.

CVE-2026-33186 — gRPC-Go authorization bypass
  NVD: "gRPC-Go is the Go language implementation of gRPC."
  We use io.grpc:* (Java); the affected `:path` parser is in
  google.golang.org/grpc, not on our classpath. CPE umbrella collision.
  Suppressed with NVD-source evidence.

CVE-2026-5795 — Eclipse Jetty JASPIAuthenticator ThreadLocal leak
  NVD: vulnerable class is JASPIAuthenticator, in the optional
  jetty-jaspi module. Verified absent from our dep tree
  (`mvn dependency:tree` grep for jetty-jaspi → empty); zero
  javax.security.auth.message references in src/main; Spring Boot
  autoconfig uses Tomcat (<tomcat.version>) for the embedded servlet
  container, not Jetty. The Jetty in our tree is brought transitively
  by Neo4j 2026.02.3 (embedded HTTP API) and does not enable JASPI.
  Suppressed with NVD-source evidence + upstream advisory link.

Each suppression entry in dependency-check-suppressions.xml carries:
- the NVD link as a primary source
- a verbatim quote of the relevant NVD scope statement
- a justification tied to our actual dep-tree / source-tree state
- TechLead sign-off (Amit Kumar, 2026-04-25)

This keeps the gate hard (failBuildOnCVSS=7) while honoring
security.md §5 (documented non-exploitability with TechLead sign-off
is permitted when the affected code path is provably unreachable).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>

* fix(bootstrap): R5 reviewer findings + log4j-api umbrella CPE bump (RAN-47)

Reviewer round-5 found 3 blockers on `6e7e911` (RAN-47 cf64b44d) plus the
CI build remained red on a single log4j-api umbrella-CPE attribution.

R5-1 — release-java.yml `git commit -S` non-interactive GPG.
  setup-java only wires MAVEN_GPG_PASSPHRASE into Maven's settings.xml;
  git itself has no equivalent autoconfig and `git commit -S` invokes
  gpg interactively by default, which fails in Actions for passphrase-
  protected keys. Configured a non-interactive gpg-agent (gpg.conf with
  pinentry-mode loopback, gpg-agent.conf with allow-loopback-pinentry)
  and wired git.gpg.program to a thin wrapper that exec's into
  `gpg --batch --yes --pinentry-mode loopback --passphrase "$MAVEN_GPG_PASSPHRASE"`.
  MAVEN_GPG_PASSPHRASE is already passed on each step that signs.

R5-2 — scripts/setup-git-signed.sh OpenPGP key-id support.
  Previous version forced an SSH-style file-existence check on
  user.signingkey, rejecting contributors whose global config uses
  gpg.format=openpgp with a key id / fingerprint. Added GIT_GPG_FORMAT
  resolution (env > global > "ssh" default) and per-format validation:
    - ssh:     existing path-on-disk check
    - openpgp: gpg --list-secret-keys must know the key
    - x509:    gpgsm --list-secret-keys must know the key
    - other:   reject with a clear error
  Maintainer's defaults are unchanged (still ssh-format).

R5-3 — first-time-setup.md fast-loop scope clarified.
  `mvn test` only runs Surefire (unit tests); this repo's integration
  tests are wired through Failsafe at `integration-test`/`verify`.
  Added a fourth `mvn verify -Dspotbugs.skip ...` form for unit +
  integration in the inner loop, plus a clarifying paragraph.

CI fix — log4j-api 2.25.3 → 2.25.4.
  CI on `6e7e911` was failing solely on:
    log4j-api-2.25.3.jar : CVE-2026-34478, CVE-2026-34480, CVE-2026-34481
  These are log4j-core CVEs attributed to log4j-api by the umbrella
  cpe:2.3:a:apache:log4j:* CPE match. log4j-core 2.25.4 was already
  pinned in dependencyManagement; mirrored the pin to log4j-api so
  the umbrella-CPE attribution clears (the API jar contains no
  vulnerable code; this is a clean trail-consistency bump, not a
  suppression). Comment on the override block updated to reflect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>

* fix(bootstrap): R5 reviewer findings 4–7 (RAN-47 fd559a54)

Reviewer's updated PR comment fd559a54 surfaced 4 additional blockers
beyond R5-1..3 already fixed in `a4dee7c`.

R5-4 — spotbugs-maven-plugin not lifecycle-bound.
  pom.xml declared the plugin but with no `<executions>` block, so
  `mvn verify` (and therefore CI on every PR) did not actually run
  SpotBugs — the engineering-standards.md "zero High/Critical
  findings" gate was a documented claim, not an enforced one. Bound
  the `check` goal to the verify phase, set explicit threshold=High
  + failOnError=true so the gate matches the documented semantic and
  cannot silently relax under future config edits.

R5-5 — rollback.md branch-protection GET→PUT schema mismatch.
  GitHub's GET /protection returns a denormalized payload (nested
  `{enabled: bool}` envelopes, `checks[].context` strings, `*.url`
  fields) that PUT does not accept verbatim. Replaced the naive
  cat-into-PUT with a documented jq filter that unwraps the envelopes,
  projects `checks[].context` into the flat `contexts[]` PUT expects,
  drops `*.url` fields, and forces `restrictions: null` for this repo.

R5-6 — engineering-standards.md §1 unenforced branch coverage claim.
  Quality-gate table claimed "≥ 85% line, ≥ 75% branch (project-wide)"
  but `pom.xml`'s jacoco rule only enforces LINE COVEREDRATIO 0.85.
  Aligned the doc to reality (LINE only). Adding a branch-coverage
  rule is a separate decision — not in scope here.

R5-7 — release.md SSH-key claims contradict GPG-via-Actions reality.
  Two stale SSH-signing references: "Source tag (annotated, ssh-signed)"
  and pre-release checklist item "Local signing key present:
  ssh-add -L | grep ...". The actual GA path is GPG/OpenPGP-signed by
  release-java.yml using the imported MAVEN_GPG_PRIVATE_KEY — no local
  SSH key required. Updated both: the source-tag descriptor now reads
  "GPG/OpenPGP-signed by release-java.yml", and the checklist item
  now verifies the GHA secrets (MAVEN_GPG_PRIVATE_KEY,
  MAVEN_GPG_PASSPHRASE) are present via `gh secret list`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>

* docs(bootstrap): R6-1 first-time-setup multi-format signing (RAN-47 67e3c224)

Reviewer 67e3c224: `first-time-setup.md` still described
`scripts/setup-git-signed.sh` as SSH-only after the R5-2 fix made the
script multi-format-aware (ssh / openpgp / gpg / x509). Onboarding
doc misled the exact contributors R5-2 was meant to unblock.

Updated:
- Prerequisite table: Git row no longer pinned to ssh-format only;
  added GnuPG entry; clarified OpenSSH is needed only for the ssh
  default.
- "Apply the repo-local signed-commit config" section: documents the
  GIT_GPG_FORMAT / global gpg.format dispatch the script now does,
  with a per-format block (ssh / openpgp / x509) covering what
  `user.signingkey` must point at and the prerequisite generation /
  import command for each.
- Sanity-check snippet: now also prints `gpg.format` and notes that
  signingkey shape varies by format (ssh: .pub path; openpgp/x509:
  key id / fingerprint).

No code change. Doc-only fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>

* ci(bootstrap): pre-warm NVD cache + retry knobs to defeat dep-check NPE

PR #74 build job (run 24930518462) hit
`NullPointerException: Cannot invoke BasicDataSource.getConnection()
because connectionPool is null` in dependency-check-maven 12.2.0
during a cold-cache run on `2d3e16d`. Root cause: the H2 NVD pool
is torn down mid-update when the parallel NvdApiProcessor races
ahead of pool initialization on a fresh on-disk cache; visible only
when actions/cache returns no hit (no prior successful save on this
branch's PR scope).

Fixes:

- ci-java.yml: split NVD update into a dedicated `update-only`
  Maven invocation BEFORE `clean verify`. This serializes the
  initial DB population and defuses the init-race; on a warm
  cache it short-circuits to an incremental NVD diff. Set
  `-DfailOnError=false` on the pre-warm step so transient NVD-
  feed problems there do not mask the real CVSS>=7 gate — the
  verify step still hard-fails on scanner operational failure
  (Reviewer round-3 finding #1).

- pom.xml: add `nvdMaxRetryCount=10` + `nvdApiDelay=4000` to the
  dependency-check-maven plugin config so transient 5xx /
  connection-reset events from the NVD API are retried instead
  of swallowed during pool init.

RAN-46 (CI gate stability for AC #5).
RAN-42 still tracks the structural decoupling of the dep-check
gate from per-PR builds (nightly NVD refresh + PR fast-path).

Co-Authored-By: Paperclip <noreply@paperclip.ing>

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant