Skip to content

Commit a4dee7c

Browse files
aksOpsclaudePaperclip-Paperclip
committed
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>
1 parent 6e7e911 commit a4dee7c

4 files changed

Lines changed: 104 additions & 18 deletions

File tree

.github/workflows/release-java.yml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
server-password: MAVEN_PASSWORD
2424
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
2525
gpg-passphrase: MAVEN_GPG_PASSPHRASE
26-
- name: Configure git identity for signed release commit and tag
26+
- name: Configure git identity and non-interactive GPG for signed commit/tag
2727
run: |
2828
git config user.email "github-actions[bot]@users.noreply.github.com"
2929
git config user.name "github-actions[bot]"
@@ -38,9 +38,36 @@ jobs:
3838
git config gpg.format openpgp
3939
git config commit.gpgsign true
4040
git config tag.gpgsign true
41+
# Reviewer finding cf64b44d (RAN-47, R5-1):
42+
# `git commit -S` / `git tag -s` invoke gpg interactively by default
43+
# and fail in non-interactive Actions shells when the imported key
44+
# has a passphrase. setup-java only wires the passphrase for Maven
45+
# signing (via MAVEN_GPG_PASSPHRASE in settings.xml); git itself
46+
# has no equivalent autoconfig. Configure the gpg-agent for loopback
47+
# pinentry, point gpg.program at a thin wrapper that injects
48+
# --batch / --pinentry-mode loopback / --passphrase from
49+
# MAVEN_GPG_PASSPHRASE, so signing succeeds non-interactively.
50+
mkdir -p "$HOME/.gnupg"
51+
chmod 700 "$HOME/.gnupg"
52+
printf '%s\n' 'use-agent' 'pinentry-mode loopback' > "$HOME/.gnupg/gpg.conf"
53+
printf '%s\n' 'allow-loopback-pinentry' > "$HOME/.gnupg/gpg-agent.conf"
54+
gpgconf --kill gpg-agent || true
55+
# Wrapper script: git invokes this with the same flags as gpg.
56+
# We exec into gpg with --batch + loopback + the passphrase from
57+
# the env (MAVEN_GPG_PASSPHRASE is set on each step that signs).
58+
cat > "$HOME/.gnupg/gpg-loopback.sh" <<'WRAPPER'
59+
#!/usr/bin/env bash
60+
# Non-interactive gpg wrapper for `git commit -S` / `git tag -s`.
61+
# MAVEN_GPG_PASSPHRASE is set on the workflow step that signs.
62+
exec gpg --batch --yes --pinentry-mode loopback \
63+
--passphrase "${MAVEN_GPG_PASSPHRASE:-}" "$@"
64+
WRAPPER
65+
chmod +x "$HOME/.gnupg/gpg-loopback.sh"
66+
git config gpg.program "$HOME/.gnupg/gpg-loopback.sh"
4167
- name: Set release version and create signed release commit
4268
env:
4369
RELEASE_VERSION: ${{ inputs.version }}
70+
# Picked up by the gpg-loopback wrapper script for `git commit -S`.
4471
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
4572
# Commit the version bump on a detached HEAD off the workflow's
4673
# checkout. The commit is reachable only via the tag created below —

pom.xml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,14 @@
6262
log4j-core 2.25.3 -> 2.25.4 (CVE-2026-34477 MOD,
6363
CVE-2026-34478 MOD,
6464
CVE-2026-34480 MOD)
65+
log4j-api 2.25.3 -> 2.25.4 (umbrella-CPE attribution
66+
of log4j-core CVEs;
67+
bumped to keep the dep
68+
tree consistent and to
69+
stop the dep-check
70+
umbrella match)
6571
log4j-layout-template-json 2.25.3 -> 2.25.4 (CVE-2026-34481 MOD)
66-
both pulled in transitively by Neo4j 2026.02.3.
72+
all three pulled in transitively by Neo4j 2026.02.3.
6773
shiro-core 2.0.6 -> 2.1.0 (CVE-2026-23901 LOW)
6874
•pulled in by neo4j-security.
6975
mcp-core 1.1.0 -> 1.1.1 (CVE-2026-34237 MOD)
@@ -77,6 +83,11 @@
7783
<artifactId>log4j-core</artifactId>
7884
<version>2.25.4</version>
7985
</dependency>
86+
<dependency>
87+
<groupId>org.apache.logging.log4j</groupId>
88+
<artifactId>log4j-api</artifactId>
89+
<version>2.25.4</version>
90+
</dependency>
8091
<dependency>
8192
<groupId>org.apache.logging.log4j</groupId>
8293
<artifactId>log4j-layout-template-json</artifactId>

scripts/setup-git-signed.sh

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
#!/usr/bin/env bash
22
# scripts/setup-git-signed.sh
33
#
4-
# Apply the repo-local git config required by RAN-46 AC #2.
4+
# Apply the repo-local git config required by RAN-46 AC #2. Supports BOTH
5+
# ssh-format and openpgp-format signing — picks up whichever the contributor
6+
# already has wired into their global git config.
57
#
6-
# user.name = Amit Kumar
7-
# user.email = ak.nitrr13@gmail.com
8+
# Defaults (when nothing is set globally):
89
# user.signingkey = ~/.ssh/id_ed25519.pub
910
# gpg.format = ssh
10-
# commit.gpgsign = true
11-
# tag.gpgsign = true
11+
#
12+
# Honored env / global-config inputs:
13+
# GIT_USER_NAME (else: git config --global user.name)
14+
# GIT_USER_EMAIL (else: git config --global user.email)
15+
# GIT_SIGNING_KEY (else: git config --global user.signingkey,
16+
# else default SSH key)
17+
# GIT_GPG_FORMAT (else: git config --global gpg.format,
18+
# else "ssh")
1219
#
1320
# Idempotent: re-running is a no-op except for the verification block at the end.
1421
# Run from the repo root (or any subdirectory of the worktree).
@@ -26,10 +33,11 @@ cd "$repo_root"
2633
# Identity is taken from env vars first, then from the user's GLOBAL git
2734
# config — never hard-coded to the maintainer. This avoids silently
2835
# misattributing every contributor's signed commits to the maintainer
29-
# (Reviewer finding #3).
36+
# (earlier Reviewer finding).
3037
GIT_USER_NAME=${GIT_USER_NAME:-$(git config --global --get user.name 2>/dev/null || true)}
3138
GIT_USER_EMAIL=${GIT_USER_EMAIL:-$(git config --global --get user.email 2>/dev/null || true)}
3239
GIT_SIGNING_KEY=${GIT_SIGNING_KEY:-$(git config --global --get user.signingkey 2>/dev/null || echo "$HOME/.ssh/id_ed25519.pub")}
40+
GIT_GPG_FORMAT=${GIT_GPG_FORMAT:-$(git config --global --get gpg.format 2>/dev/null || echo "ssh")}
3341

3442
if [ -z "$GIT_USER_NAME" ] || [ -z "$GIT_USER_EMAIL" ]; then
3543
cat >&2 <<'EOF'
@@ -48,10 +56,17 @@ EOF
4856
exit 4
4957
fi
5058

51-
# The signing key path must exist before we wire up signing — otherwise every
52-
# commit will fail and the local config will be silently broken.
53-
if [ ! -f "$GIT_SIGNING_KEY" ]; then
54-
cat >&2 <<EOF
59+
# Signing-key validation depends on gpg.format:
60+
# - ssh: user.signingkey is a path on disk (the file must exist)
61+
# - openpgp: user.signingkey is a key id / fingerprint (gpg must know it)
62+
# - x509: user.signingkey is a key id / fingerprint (gpgsm must know it)
63+
# Reviewer finding cf64b44d (RAN-47, R5-2): the previous version forced the
64+
# ssh-path check unconditionally, which rejected contributors using OpenPGP
65+
# globally even when their key chain was healthy.
66+
case "$GIT_GPG_FORMAT" in
67+
ssh)
68+
if [ ! -f "$GIT_SIGNING_KEY" ]; then
69+
cat >&2 <<EOF
5570
error: SSH signing key not found at $GIT_SIGNING_KEY
5671
5772
Generate one with:
@@ -60,8 +75,39 @@ Then upload the public key (\$GIT_SIGNING_KEY) to your GitHub account under:
6075
Settings → SSH and GPG keys → New SSH key → Key type: Signing Key
6176
And re-run this script.
6277
EOF
63-
exit 2
64-
fi
78+
exit 2
79+
fi
80+
;;
81+
openpgp|gpg)
82+
if ! gpg --list-secret-keys --with-colons "$GIT_SIGNING_KEY" 2>/dev/null | grep -q '^sec:'; then
83+
cat >&2 <<EOF
84+
error: OpenPGP signing key '$GIT_SIGNING_KEY' not found in your gpg keyring.
85+
86+
Either point user.signingkey at a key id / fingerprint that
87+
\`gpg --list-secret-keys\` knows, or generate / import a key first:
88+
gpg --full-generate-key
89+
git config --global user.signingkey <KEY_ID>
90+
And re-run this script.
91+
EOF
92+
exit 2
93+
fi
94+
;;
95+
x509)
96+
if ! gpgsm --list-secret-keys "$GIT_SIGNING_KEY" >/dev/null 2>&1; then
97+
cat >&2 <<EOF
98+
error: x509 signing key '$GIT_SIGNING_KEY' not found via gpgsm.
99+
100+
Configure x509 signing keys in gpgsm and ensure
101+
\`gpgsm --list-secret-keys\` reports your key, then re-run.
102+
EOF
103+
exit 2
104+
fi
105+
;;
106+
*)
107+
echo "error: unsupported gpg.format '$GIT_GPG_FORMAT' (expected ssh, openpgp, gpg, or x509)." >&2
108+
exit 5
109+
;;
110+
esac
65111

66112
apply() {
67113
local key="$1" value="$2"
@@ -71,7 +117,7 @@ apply() {
71117
apply user.name "$GIT_USER_NAME"
72118
apply user.email "$GIT_USER_EMAIL"
73119
apply user.signingkey "$GIT_SIGNING_KEY"
74-
apply gpg.format ssh
120+
apply gpg.format "$GIT_GPG_FORMAT"
75121
apply commit.gpgsign true
76122
apply tag.gpgsign true
77123

shared/runbooks/first-time-setup.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,14 @@ For a faster inner loop while iterating:
8989

9090
```bash
9191
mvn -B -ntp test \
92-
-Dspotbugs.skip=true -Ddependency-check.skip=true # unit + integration, no static analysis / CVE plugins
93-
mvn -B -ntp -Dtest=SomeDetectorTest test # single test class
92+
-Dspotbugs.skip=true -Ddependency-check.skip=true # unit tests only (Surefire), no static analysis / CVE plugins
93+
mvn -B -ntp -Dtest=SomeDetectorTest test # single unit test class
9494
mvn -B -ntp -DskipTests=true package # JAR only, no tests
95+
mvn -B -ntp verify \
96+
-Dspotbugs.skip=true -Ddependency-check.skip=true # unit + integration tests (Surefire + Failsafe), no static analysis / CVE plugins
9597
```
9698

97-
The first command **does run tests** — earlier drafts incorrectly passed `-DskipTests` here, which would have skipped them. Use `-Dspotbugs.skip` / `-Ddependency-check.skip` to keep the inner loop fast without dropping test coverage.
99+
The first command **does run tests** — earlier drafts incorrectly passed `-DskipTests` here, which would have skipped them. Reviewer finding cf64b44d (RAN-47, R5-3): Maven's `test` phase only runs Surefire (unit tests). This repo's integration tests are wired through Failsafe at the `integration-test` / `verify` phases — use the fourth form above when you need both unit + integration in the inner loop. Use `-Dspotbugs.skip` / `-Ddependency-check.skip` to keep things fast without dropping test coverage.
98100

99101
Smoke-test the CLI end-to-end against this repo:
100102

0 commit comments

Comments
 (0)