Skip to content

Add java-security: eight Java rules as one policy, picked per rule - #95

Merged
jothimani-rajendran merged 2 commits into
mainfrom
claude/java-security-policy
Sep 22, 2026
Merged

jothimani-rajendran merged 2 commits into
mainfrom
claude/java-security-policy

Conversation

@jothimani-rajendran

Copy link
Copy Markdown
Collaborator

What

base/java-security/, new. The Java security engine from open-coder-ai/chock-java-security, moved into the catalog as one policy folder carrying all eight rules (MyBatis ${} interpolation, unescaped template output, Jackson default typing / XStream without an allowlist, wildcard CORS origin with credentials, wildcard actuator exposure, unverified JWT parse, request-chosen file path, ObjectInputStream over request bytes). An adopter picks and chooses per rule in .chock/security.json (allow|deny|ask; a rule the file does not name denies), never per policy folder, so a ninth rule is a version bump here rather than a ninth folder. The file carries verdicts only: a pattern, severity or path in it is refused at the next commit.

What an adopter sees:

  • At commit: implementations/java-security-pre-commit.py (a hook.script on [commit], the shape no-a11y-regression established) reads the staged revision through the vendored engine beside it and refuses on a deny, on an ask with no terminal, on an unreadable selection, and on any failure inside the engine. No path in it allows what it never judged. Ceiling enforced-at-commit, as the registry and the regenerated policy page now say.
  • In context: two lines of ambient rule text naming the eight constructs and the selection contract.
  • Pick and choose: skills/configure-java-security/, the guided page walked in the agent's own panel (as an Artifact with a db store where the client can publish one), whose submit becomes the selection file. Its embedded contract is checked against the shipped rules in CI.
  • Not yet: the write-path doors (refusing the construct at tool use and at the turn's end). Those reach this policy through the engine's kind: script gate, feat(gate): add a script kind that runs a policy's own program chock#154, once this catalog adopts a release carrying it; the eval cases are written in the staged-files shape that gate will replay, and until then tools/check_java_security.py runs every one of them against the shipped guard.

Also in this PR, because the policy exposed them:

  • tools/gen_policy_docs.py classifies through tools/mechanism.py instead of its own gate/guard/text copy, so a commit-time script policy's page says it enforces at commit instead of "There is no mechanism". docs/no-a11y-regression/README.md changes accordingly (it was understating itself the same way).
  • docs/figures/make_enforcement.py reads only the registry's policies: records; the new skills: section has no enforces label and aborted the render.
  • CI gains one step, python tools/check_java_security.py, beside the two a11y checks.

Definition of done

  • chock check clean (this repo: 0 errors; the staged adopter with every published policy and the skill: 0 errors, 0 warnings beyond the pre-existing INDEX budget notice and INT-3's verb suggestion for configure-java-security)
  • chock check --only evals green (this repo and the staged adopter: 409 pass, 202 skipped)
  • chock sync --repo . --check clean; chock sync added the skill to .agents/policies/INDEX.md and .chock/registry.json
  • python tools/gen_policy_docs.py --check and python tools/check_readme.py pass (42 policies, 20 enforced, 22 advisory); check_registry, check_console, check_workflows, check_effects (11 guard-shipping policies incl. this one), gen_coverage_matrix --check, brand assets --check, figures regenerated without drift, chock plugin build --check for all three trees, adoption transcript docs/java-security/adoption.md reproduces
  • The policy claims only what it can do: enforced-at-commit from a script that exits non-zero; the write path is stated as not yet reached
  • At least one authored eval case that could have failed: 28 authored cases in evals/suite.yaml, each rule with its trigger and its correct sibling; none has an executable form on this engine (a hook.script is not replayed by the eval runner), so tools/check_java_security.py executes 52 ported cases plus the commit path and the setup page, 83 checks, in CI

If this touches implementations/

  • I understand this script becomes a git hook that runs on every commit in an adopter's repository, and a guard consulted before their agent runs a command
  • The script is read in full by a reviewer, not just the diff. What to read: implementations/java-security-pre-commit.py (14 lines, the entry point) and implementations/chock_security/ (the engine: decision.py, engine.py, selection.py, pack.py, flow.py, rules/*.py, frontends/precommit.py, data/java.json). Standard library only; no network, no secrets, no eval/exec; it reads git and the selection file and writes nothing (check_effects.py observed that).

Known residuals, stated rather than left to be found:

  • INT-3 warns that configure-java-security does not start with a verb it recognises. Kept: the id is what a person says when they want it.
  • The setup page's footer still mentions chock-security setup apply, the plugin form's CLI; in the catalog the skill's procedure writes the selection file directly and says so. The page is otherwise byte-identical to the plugin's, with an agent-neutral contract.
  • The engine lives in two places until chock-java-security is retired; this copy is the one the catalog checks.

🤖 Generated with Claude Code


Generated by Claude Code

Moves the Java security engine from open-coder-ai/chock-java-security into
the catalog as one policy folder, base/java-security/. All eight rules ship
together and an adopter chooses per rule in .chock/security.json
(allow|deny|ask, silence denies), so a ninth rule is a version bump of this
policy rather than a ninth folder. The selection file carries verdicts only;
a pattern or severity in it is refused at the next commit.

The guard, implementations/java-security-pre-commit.py, is a hook.script on
[commit] in the shape no-a11y-regression established: it reads the staged
revision through the vendored engine beside it and refuses on a deny, on an
ask with no terminal, on an unreadable selection, and on any failure inside
the engine. The write-path doors (tool use, turn end) arrive through the
engine's `kind: script` gate once the catalog adopts a release carrying it.

skills/configure-java-security/ is the pick-and-choose door: the guided
page, walked in the agent's own panel, whose submit becomes the selection
file. Its embedded contract is checked against the shipped rules.

tools/check_java_security.py runs 52 cases ported from the engine's suite
-- every rule's trigger and its correct sibling -- plus the commit path in
a throwaway repository, in CI. tools/gen_policy_docs.py now classifies
through tools/mechanism.py, so a commit-time script policy's page says it
enforces instead of "no mechanism" (no-a11y-regression's page changes too).
docs/figures/make_enforcement.py reads only the registry's policy records,
since a skills: section carries no enforces label.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
@jothimani-rajendran
jothimani-rajendran marked this pull request as ready for review September 22, 2026 13:42
@jothimani-rajendran
jothimani-rajendran merged commit efaac25 into main Sep 22, 2026
13 checks passed
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.

2 participants