Skip to content

C1-JO-F1 — fail closed on unreadable push force - #54

Merged
LogicDuke merged 1 commit into
reconcile/pr009-main-556144bfrom
repair/pr053-job-operation-force-unreadable
Aug 24, 2026
Merged

C1-JO-F1 — fail closed on unreadable push force#54
LogicDuke merged 1 commit into
reconcile/pr009-main-556144bfrom
repair/pr053-job-operation-force-unreadable

Conversation

@LogicDuke

@LogicDuke LogicDuke commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Finding

Verified defect

A repair.push request whose own force operand is present but unreadable collapses to force: false and receives ALLOW_ONCE, instead of failing closed. The shared guarded reader readOwnProperty reports both an absent property and a throwing read as undefined, and the value-only force parser treated undefined as non-forced — so ABSENT and PRESENT-BUT-UNREADABLE collapsed into the same non-forced default, contradicting the documented invariant that only an absent or literally false force is non-forced.

Family sweep

force is the sole violating security-relevant scalar. Every sibling operand (operation, requestId, jobId, repositoryId, parentPullRequestId, parentHeadSha, worktreeId, path, commandClass, ref, sourceRef, targetRef) already fails closed to a null/unknown → DENY state. The shared readOwnProperty contract is left unchanged.

Required semantics (all verified after fix)

  • absent → preserve non-forced behavior (ALLOW_ONCE)
  • false → preserve non-forced behavior (ALLOW_ONCE)
  • true → DENY / FORCE_PUSH_FORBIDDEN
  • present undefined (own data or getter) → DENY
  • unreadable getter (throws) → DENY
  • Proxy get / getOwnPropertyDescriptor read failure → DENY
  • all other present non-false values (0, '', null, 'false', object) → DENY

The force operand is read at most once per readJobOperation (getter invoked ≤1×), the snapshot stays total and never throws, and a force-only read failure does not turn the whole request unreadable. No denied case issues a permit.

Change scope

Two files only:

  • src/domain/job-operation.ts — presence-aware, fail-closed readForceFlag (module-private); Object.hasOwn captured at module load; single call-site update.
  • tests/domain/job-authorization-invariants.test.ts — focused C1-JO-F1 regression cases.

Validation

  • Fail-before reproduced; pass-after confirmed across the full matrix.
  • Fresh independent validation: PASS.
  • Second-order closure: PASS.
  • Full suite 1651 passed · typecheck 0 · lint 0 · build 0 · git diff --check 0.
  • No public API change · no dependency change · no authority-model widening.

Excluded

Summary by CodeRabbit

  • Bug Fixes
    • Push authorization now safely distinguishes between an omitted force setting and a provided value.
    • Pushes are denied when the force setting is unreadable, unavailable, or contains any value other than false.
    • Invalid or inaccessible force settings no longer cause unexpected errors.
    • Requests with readable operation details continue to receive a clear forced-push denial when only the force setting cannot be read.
    • Valid unforced requests remain authorized as expected.

A repair.push request whose own `force` operand is present but unreadable —
an own getter or Proxy trap that throws, a getter that returns `undefined`, an
own data property of `undefined`, or a presence check that throws — normalized
to `force: false` and received ALLOW_ONCE, because the shared guarded reader
reports both absence and a throwing read as `undefined` and the value-only
force parser treated `undefined` as non-forced. Absence and present-but-
unreadable collapsed into the same non-forced default, contradicting the
documented invariant that only an absent or literally `false` force is
non-forced.

Replace the value-only parser with a presence-aware, fail-closed force reader
local to job-operation.ts: an absent own `force` stays non-forced, a present
own `force` is read at most once and is non-forced only when it reads as
literally `false`, and any unreadable presence check or read fails closed to
forced. `Object.hasOwn` is captured at module load. The shared
`readOwnProperty` contract is unchanged; every other operand already fails
closed. C1-JO-F1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 03fad72e-24f9-44d0-bc5e-462fba6f4bd7

📥 Commits

Reviewing files that changed from the base of the PR and between 5accbca and 15a35cc.

📒 Files selected for processing (2)
  • src/domain/job-operation.ts
  • tests/domain/job-authorization-invariants.test.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The job operation reader now distinguishes an absent force property from present but unreadable values. Only absent or literal false is unforced. Authorization tests cover normal and hostile property access cases.

Changes

Push force authorization

Layer / File(s) Summary
Presence-aware force reader
src/domain/job-operation.ts
The reader captures Object.hasOwn, checks property presence before reading force, and treats unreadable or non-false present values as forced. readJobOperation passes the request record to this reader.
Authorization invariant coverage
tests/domain/job-authorization-invariants.test.ts
Tests cover absent, false, non-false, getter, throwing getter, and Proxy force values. They also verify denial details, single reads, and normalization of other request fields.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to 15a35

The change makes unreadable force values fail closed while preserving existing non-forced behavior, with focused validation reported as passing; no actionable merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant Request
  participant readJobOperation
  participant readForceFlag
  participant Authorization
  Request->>readJobOperation: provide request record
  readJobOperation->>readForceFlag: pass request record
  readForceFlag-->>readJobOperation: return normalized force state
  readJobOperation->>Authorization: provide normalized operation
  Authorization-->>Request: allow unforced or deny forced push
Loading

Poem

I’m a rabbit guarding force at night,
False stays calm, and absent stays light.
A getter that snaps, a Proxy that cries,
Turns into denial before it flies.
The job fields remain neat in a row—
Safe little paws say “no” when unsure.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: fail-closed handling for unreadable push force values.
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch repair/pr053-job-operation-force-unreadable

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@LogicDuke
LogicDuke marked this pull request as ready for review August 24, 2026 11:14
@LogicDuke

Copy link
Copy Markdown
Owner Author

@codex review

@LogicDuke

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 15a35cc1f5

ℹ️ 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".

@LogicDuke
LogicDuke merged commit 89ca7ba into reconcile/pr009-main-556144b Aug 24, 2026
2 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.

1 participant