Skip to content

fix(AF-1102): fail closed on OTHER statements in denied_columns - #1103

Merged
babltiga merged 2 commits into
mainfrom
fix/AF-1102-denied-columns-other-members
Sep 25, 2026
Merged

babltiga merged 2 commits into
mainfrom
fix/AF-1102-denied-columns-other-members

Conversation

@babltiga

Copy link
Copy Markdown
Contributor

Closes #1102

What

core.api.DeniedColumns.rejected no longer skips OTHER statements. OTHER (MERGE, CALL, …) is never column-analysed by SqlParserServiceImpl, so it now fails closed like any unanalysed parse: it reaches every denied entry. It is treated that way even if a parse result claims columnsAnalyzed=true.

Why

The old early return assumed no permission grants OTHER. That holds for standalone queries, but DefaultRequestGroupService.validatePermission admits an OTHER member for a non-admin holding only can_write (or can_break_glass in a break-glass group). verifyTableAndColumnScope then called DeniedColumns.rejected, which returned nothing. As a result, MERGE INTO t USING (SELECT ssn FROM users) s … bypassed a denied_columns = [users.ssn] grant. This is the same short-circuit #1101 (#940) fixed in DeniedShapes.

Reviewer notes

  • Every entry, not only entries on referenced tables. The table set for OTHER isn't reliable: a CALL can read tables it never names, and a statement the inspector can't walk yields an empty set. So an OTHER member is refused whenever denied_columns is non-empty.
  • Only request groups change. Standalone submission, the recurring recheck, dry-run and the access simulator already refuse OTHER at the capability check, before this matcher runs.
  • Tests. DeniedColumnsTest replaces the assertion that "OTHER is never checked" with two cases: CALL reaches every entry, and a MERGE parse marked analysed still fails closed. DefaultRequestGroupServiceCrudTest adds a normal (can_write-only) and a break-glass MERGE member case; both are refused naming users.ssn, and the group never changes state.
  • Docs. The denied_columns semantics are updated in docs/04-api-spec.md, docs/07-security.md (the section and the enforcement flow chart) and docs/05-backend.md (the "Matching" bullet).

Local: the full backend unit suite passes (mvn test -Dtest='!*IntegrationTest', 9,049 tests, including ApplicationModulesTest and ApiPackageDependencyTest). Integration tests were not run locally.

DeniedColumns.rejected skipped OTHER on the premise that no permission grants it, but a request-group member admits MERGE/CALL under can_write (can_break_glass for break-glass groups), so MERGE … USING (SELECT ssn FROM users) bypassed a users.ssn denial. OTHER is never column-analysed, so it now reaches every denied entry, like any unanalysed parse (mirrors DeniedShapes in #1101).

Closes #1102
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Backend Test Results

10 508 tests  +4   10 508 ✅ +4   11m 26s ⏱️ -15s
 1 150 suites ±0        0 💤 ±0 
 1 150 files   ±0        0 ❌ ±0 

Results for commit 9ce885c. ± Comparison against base commit 4d28670.

This pull request removes 1 and adds 5 tests. Note that renamed tests count towards both.
com.bablsoft.accessflow.core.api.DeniedColumnsTest ‑ unanalyzedDdlFailsClosedAndOtherIsNeverChecked
com.bablsoft.accessflow.core.api.DeniedColumnsTest ‑ otherStatementFailsClosedEvenWhenMarkedAnalyzed
com.bablsoft.accessflow.core.api.DeniedColumnsTest ‑ otherStatementReachesEveryDeniedEntry
com.bablsoft.accessflow.core.api.DeniedColumnsTest ‑ unanalyzedDdlFailsClosed
com.bablsoft.accessflow.requestgroups.internal.DefaultRequestGroupServiceCrudTest ‑ breakGlassSubmitAlsoRejectsAnOtherMemberWhenTheSubmitterIsDeniedAColumn
com.bablsoft.accessflow.requestgroups.internal.DefaultRequestGroupServiceCrudTest ‑ submitRejectsAnOtherMemberWhenTheSubmitterIsDeniedAColumn

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Backend Code Coverage

Overall Project 94.8% 🍏
Files changed 100% 🍏

File Coverage
DeniedColumns.java 99.8% 🍏

…lumns-other-members

# Conflicts:
#	backend/src/test/java/com/bablsoft/accessflow/requestgroups/internal/DefaultRequestGroupServiceCrudTest.java
@babltiga
babltiga merged commit 6ef991b into main Sep 25, 2026
54 of 56 checks passed
@babltiga
babltiga deleted the fix/AF-1102-denied-columns-other-members branch September 25, 2026 08:36
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.

Denied columns skipped for OTHER request-group members (MERGE/CALL)

1 participant