Skip to content

feat: add bounded canonical identity validator - #84

Closed
Pigbibi wants to merge 5 commits into
mainfrom
codex/canonical-typed-identity-r1b
Closed

feat: add bounded canonical identity validator#84
Pigbibi wants to merge 5 commits into
mainfrom
codex/canonical-typed-identity-r1b

Conversation

@Pigbibi

@Pigbibi Pigbibi commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a pure typed canonical identity validator and verified-record boundary
  • reject high-confidence secret markers without broad substring matching
  • keep severity outside verified identity records
  • enforce identifier (:: identifier)* anchors

Scope

Fresh R1b replacement for frozen PR #83. No runtime, history, evidence, reviewer adapter, workflow, or R2 integration.

Validation

  • python3 -m unittest tests.test_canonical_typed_identity_r1b (5 passed)
  • python3 -m unittest tests.test_run_codex_pr_review (54 passed)
  • python3 -m unittest discover tests (625 passed, 1 skipped)
  • python3 -m ruff check .
  • python3 -m compileall -q service scripts tests
  • actionlint .github/workflows/*.yml
  • git diff --check origin/main...HEAD

Co-Authored-By: Codex <noreply@openai.com>
@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown

🤖 Codex PR Review

Merge allowed: No issues found


Review by Codex PR Review bot • PR

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 650167b696

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/canonical_typed_identity.py Outdated
raise IdentityError("invalid secret reference")
return {"kind": kind, "value": {"type": typ, "role": role, "position": position}}
item = _text(token["value"])
if any(marker in item.lower() for marker in MARKERS):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Narrow secret-prefix matching to token boundaries

When a legitimate identifier contains sk- as part of a normal word, such as task-handler or risk-score, this substring check rejects the payload as a reserved secret before the identifier regex runs. Since hyphenated identifiers are otherwise allowed, this can make valid contract anchors or predicates unusable whenever common names happen to contain one of these short prefixes; the marker check should require a credential-shaped token or at least a segment/start boundary rather than any substring occurrence.

Useful? React with 👍 / 👎.

Comment thread scripts/canonical_typed_identity.py Outdated
raise IdentityError("invalid object fields")
return value
def _text(value: Any, limit: int = 512) -> str:
if not isinstance(value, str) or len(value) > limit or len(value.encode()) > limit:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle unpaired surrogates as validation errors

When this validator is fed JSON-decoded input containing an escaped unpaired surrogate, for example in scope.file or a token value, value.encode() raises UnicodeEncodeError before the control-character check can raise IdentityError. Callers that treat IdentityError as the closed validation failure will instead get an unexpected exception or 500 for malformed text, so the length check should reject surrogates before encoding or catch encoding errors and re-raise IdentityError.

Useful? React with 👍 / 👎.

fields = {"schema", "canonicalizer_version", "scope", "anchors", "predicates", "required_behavior", "forbidden_behavior", "ordering_constraints", "contract_key", "behavior_digest", "fingerprint_v2"}
if not isinstance(record, dict) or set(record) != fields or any(not isinstance(record[name], str) or not DIGEST.fullmatch(record[name]) for name in fields - {"schema", "canonicalizer_version", "scope", "anchors", "predicates", "required_behavior", "forbidden_behavior", "ordering_constraints"}):
raise IdentityError("invalid verified record")
identity = validate_identity({name: record[name] for name in fields - {"contract_key", "behavior_digest", "fingerprint_v2"}})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject non-canonical records during verification

When a record contains fields that normalize to the canonical payload but are not themselves canonical, such as an uppercase scope.repo paired with the digest for the lowercase repo, verification still succeeds because this revalidates a normalized copy and only compares the digests. That means the verified-record boundary accepts multiple on-wire records for one fingerprint, so any caller that stores or compares the supplied record can treat bytes not actually covered by the fingerprint as verified; compare the record to identity.as_record() before returning.

Useful? React with 👍 / 👎.

Co-Authored-By: Codex <noreply@openai.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2fc8e7336f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +73 to +76
typ, role, position = _text(ref["type"], 32), _text(ref["role"], 32), ref["position"]
if not re.fullmatch(r"[a-z][a-z0-9_.-]{0,31}", typ) or not re.fullmatch(r"[a-z][a-z0-9_.-]{0,31}", role) or isinstance(position, bool) or not isinstance(position, int) or not 0 <= position <= 1024:
raise IdentityError("invalid secret reference")
return {"kind": kind, "value": {"type": typ, "role": role, "position": position}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject secret markers in secret_ref metadata

When a secret_ref is built from untrusted extraction output, the type or role fields can still carry a literal high-confidence token (for example role="sk-proj-1234567890abcdef" or a github_pat_... value) because this branch validates only the lowercase shape and returns before running SECRET_PATTERNS. That metadata is emitted unchanged by as_record() and covered by the digest, so the secret-safe reference path can still leak the secret; apply the same marker rejection to these fields before returning.

Useful? React with 👍 / 👎.

Co-Authored-By: Codex <noreply@openai.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea19ccc849

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

parts = repo.split("/")
if len(parts) != 2 or not OWNER.fullmatch(parts[0]) or "--" in parts[0] or not REPO.fullmatch(parts[1]) or parts[1] in {".", ".."}:
raise IdentityError("invalid repo")
path = _text(scope["file"], 1024)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject secret-shaped scope paths

When scope.file comes from untrusted extraction or repo metadata and contains a credential-shaped segment such as leaks/sk-proj-1234567890abcdef.py, this path is only normalized as text and then as_record() emits it unchanged, while the secret-marker guard is only applied to token values. That bypasses the validator's secret-safe boundary for verified records; apply the same SECRET_PATTERNS check to scope text before returning the canonical scope.

Useful? React with 👍 / 👎.

Comment thread scripts/canonical_typed_identity.py Outdated
Comment on lines +20 to +23
re.compile(r"(?<![A-Za-z0-9_])(?:github_pat_|gh[pours]_)[A-Za-z0-9_]{8,}", re.I),
re.compile(r"(?<![A-Za-z0-9_])(?:AKIA|ASIA)[A-Z0-9]{16}(?![A-Za-z0-9_])"),
re.compile(r"(?<![A-Za-z0-9_])eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+(?![A-Za-z0-9_])"),
re.compile(r"(?<![A-Za-z0-9_])sk-[A-Za-z0-9_-]{16,}(?![A-Za-z0-9_])"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat underscores as secret delimiters

When an extracted identifier embeds a real token next to underscores, such as api_sk-proj-1234567890abcdef, the negative lookbehind/lookahead treats _ as part of the surrounding word so none of these patterns match, while the identifier grammar accepts underscores and the record is emitted unchanged. This leaves the token-value secret guard bypassable for common variable-name shapes; consider allowing _ to act as a segment boundary for credential-shaped substrings.

Useful? React with 👍 / 👎.

Pigbibi and others added 2 commits July 13, 2026 09:27
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f0fc708ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

IDENTIFIER = re.compile(r"^[A-Za-z_][A-Za-z0-9_.-]*(?:\(\))?$")
DIGEST = re.compile(r"^[0-9a-f]{64}$")
SECRET_PATTERNS = (
re.compile(r"(?<![A-Za-z0-9])(?:github_pat_|gh[pours]_)[A-Za-z0-9_]{8,}", re.I),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Require full GitHub token shapes before rejecting identifiers

Fresh evidence after the earlier boundary fix: this GitHub marker still requires only eight word characters after ghs_/github_pat_, so a valid identifier or file/repo segment such as ghs_database or github_pat_validator passes the identifier/path grammar but is rejected as a secret. Any contracts anchored on GitHub-token handling code will be unusable even though no credential-shaped token is present; require the real token length/structure (or another entropy check) before raising.

Useful? React with 👍 / 👎.

@Pigbibi

Pigbibi commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by merged PR #87. This PR remains unmerged; its implementation is not imported.

@Pigbibi Pigbibi closed this Jul 13, 2026
@Pigbibi
Pigbibi deleted the codex/canonical-typed-identity-r1b branch July 13, 2026 15:56
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