Skip to content

fix(capture-core): reject duplicate JSON keys and non-finite numbers in load_state/sha_mapping and check seal.alg in check_seal (#366) - #370

Open
drk-ram wants to merge 1 commit into
agentrust-io:mainfrom
drk-ram:drk-ram-fix-capture-core-366
Open

drk-ram wants to merge 1 commit into
agentrust-io:mainfrom
drk-ram:drk-ram-fix-capture-core-366

Conversation

@drk-ram

@drk-ram drk-ram commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Reject duplicate JSON object keys and NaN/Infinity constants in agentrust_capture_core.state.load_state (returning None) and pass allow_nan=False in agentrust_capture_core.hashing.sha_mapping.
  • Verify seal.get("alg") == "SHA-256" when "alg" is present in agentrust_capture_core.seal.check_seal (returning INTEGRITY_BROKEN on algorithm mismatch).

Closes #366

Validation

  • python -m pytest packages/agentrust-capture-core/tests/test_core.py -q

@drk-ram
drk-ram requested review from a team, carloshvp and imran-siddique as code owners October 23, 2026 23:08
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

🟡 Contributor Check: MEDIUM

Check Result
Profile MEDIUM
Credential LOW
Overall MEDIUM

Automated check by AgenTrust Contributor Check.

@github-actions github-actions Bot added the needs-review:MEDIUM Contributor check flagged MEDIUM risk label Oct 23, 2026
carloshvp
carloshvp previously approved these changes Oct 24, 2026

@carloshvp carloshvp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head e8ff9802582d6738ac8e713c58ff0f5581ca928d in an isolated checkout.

The capture-core changes reject non-finite values before hashing, refuse duplicate/non-finite persisted JSON, and check a present seal algorithm while retaining the established legacy behavior when that field is absent. Existing valid seal/state controls and the new malformed-input cases pass. No blocking finding in the changed package.

Validation: all 56 package tests passed, scoped Ruff and diff whitespace checks passed, and all PR commits carry sign-offs. This approval does not establish completion of hosted CI or the maintainer policy gate.

Reviewed with OpenAI Codex.

@carloshvp

Copy link
Copy Markdown
Member

Hosted CI follow-up at head e8ff9802582d6738ac8e713c58ff0f5581ca928d: after I approved the held capture-core run, its Python 3.9 job failed in actions/setup-python before dependency installation or tests: "The version '3.9' with architecture 'x64' was not found for Ubuntu 26.04." Job: https://github.com/agentrust-io/integrations/actions/runs/40037909203/job/120848920852.

The current actions/python-versions manifest publishes Python 3.9.25 x64 builds for Ubuntu 22.04 and 24.04, so pinning this compatibility job to ubuntu-24.04 is a concrete way to retain the declared 3.9 coverage: https://github.com/actions/python-versions/blob/9834b4e4911ca2950ff6c3b7547f09eacc006848/versions-manifest.json. This runner setup failure is separate from the package source review and its 56 locally passing tests.

@rajnisht7 rajnisht7 left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the overall changes looks good, but still some places need hardening:

  • load_state still accepts exponent overflow, 1e309, -1e309, 1e999 etc. are parsed as inf/-inf instead of being rejected. parse_constant only catches literal NaN/Infinity. Need a validating parse_float with math.isfinite.
  • check_seal can now raise, because of allow_nan=False in sha_mapping, a snapshot containing nan/inf makes check_seal raise ValueError. This breaks the documented “Never raises” contract. It should return INTEGRITY_BROKEN instead. Especially bad when combined with (1): load_state accepts 1e309 -> later check_seal raises.
  • save_state still writes non-finite JSON, It uses the default allow_nan=True, so it can write files that load_state immediately rejects. Prefer allow_nan=False here too.

Current test covers duplicate key + literal NaN + wrong alg, but misses:

  • 1e309 / -1e309
  • nested overflow
  • check_seal with in-memory nan/inf (must not raise, must return BROKEN)
  • save_state with non-finite values

also rebase branch on main

@dinakarjs dinakarjs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Source follow-up at e8ff980, supporting the distinct entry-point checks in Rajnish's latest review. The diff adds parse_constant rejection and allow_nan=False for hashing, but those changes need to preserve the public load/save/check contracts together.

Please use separate regression cases for exponent overflow (including nested values), direct in-memory non-finite input to check_seal, and attempted non-finite save_state output. Preserve the expected outcomes separately: corrupt loads return None; seal verification returns INTEGRITY_BROKEN without raising; a refused save should leave an existing valid destination intact. Retain a finite save/load/seal positive control.

The combined added test can stop at its first failure, so independently collected cases would make each boundary observable. This is source inspection and follow-up to the existing review, not a fresh execution or an additional independently reproduced defect. Reviewed with OpenAI Codex.

…in load_state/save_state/sha_mapping and preserve check_seal contract (agentrust-io#366)

- Reject duplicate JSON object keys, NaN/Infinity constants, and float
  exponent overflow (parse_float with math.isfinite) in load_state,
  returning None.
- Pass allow_nan=False in save_state and sha_mapping so non-finite floats
  are refused before writing or hashing.
- Catch (ValueError, TypeError) around state_digest in check_seal and
  verify seal.get("alg") == "SHA-256" when "alg" is present so in-memory
  non-finite snapshots return INTEGRITY_BROKEN without raising.

Closes agentrust-io#366

Signed-off-by: Raghuvar Karthik Durga <177662415+drk-ram@users.noreply.github.com>
@drk-ram

drk-ram commented Oct 29, 2026

Copy link
Copy Markdown
Contributor Author

@rajnisht7 @dinakarjs @carloshvp Rebased onto origin/main and updated at 4e9cec9:

  1. Exponent overflow in load_state (state.py): Added _finite_float (parse_float=_finite_float) using math.isfinite so float exponent overflow (1e309, -1e309, 1e999, including nested values) raises ValueError inside the parser and causes load_state to return None.
  2. Preserve check_seal "Never raises" contract (seal.py): Caught (ValueError, TypeError) around state_digest(snapshot) in check_seal so an in-memory snapshot containing nan or inf returns INTEGRITY_BROKEN instead of raising ValueError.
  3. Refuse non-finite JSON in save_state (state.py): Passed allow_nan=False to json.dumps in save_state so attempting to persist non-finite values raises ValueError before atomic_write touches the destination path.
  4. Independent regression cases (tests/test_core.py): Split the regressions into separate parametrized test functions covering load_state exponent overflow (including nested), load_state non-finite constants, load_state duplicate keys, check_seal on in-memory nan/inf returning INTEGRITY_BROKEN without raising, save_state with non-finite floats raising ValueError while preserving an existing valid sealed baseline on disk, and a finite save_baseline/load_state/check_seal positive control (75 passed, 1 skipped).

@dinakarjs dinakarjs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed exact head 4e9cec9 on Linux/Python 3.12.14.

The load/save/seal contracts now agree: corrupt and exponent-overflow loads return None, direct non-finite snapshots return INTEGRITY_BROKEN, and refused non-finite saves preserve an existing destination. Separate regressions and a finite round-trip control are present. Fresh hash-locked capture-core environment: 76 tests pass; syntax/error lint selection and whitespace pass. The earlier contract/coverage follow-up is addressed. This review covers the capture-core software change; unrelated example integrations and hosted merge gates remain separate.

Reviewed with OpenAI Codex.

@carloshvp carloshvp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 4e9cec9d658692626973550f5825fd208a7c89a1 in an isolated checkout.

The persisted-state parser rejects duplicate members, literal non-finite constants and exponent overflow; saving non-finite in-memory data preserves the prior valid file. Seal checking returns a broken verdict rather than leaking a numeric-serialization error, and a present unsupported seal algorithm is refused. All 76 package tests and 60 root tests pass.

The repository CI Ruff selection and whitespace checks pass; all PR commits carry DCO sign-offs. This approves the bounded software scope. Current-head hosted checks and maintainer requirements remain applicable.

Reviewed with OpenAI Codex.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-review:MEDIUM Contributor check flagged MEDIUM risk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(capture-core): reject duplicate JSON keys and non-finite numbers in load_state/sha_mapping and check seal.alg in check_seal

4 participants