feat(AF-938): record the calling application on requests and audit rows - #1096
Merged
Merged
Conversation
Contributor
Frontend Test Results 1 files 310 suites 7m 32s ⏱️ Results for commit 53bfb66. |
Contributor
Coverage Report for Frontend Coverage (frontend)
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||
Contributor
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #938
What
Records which application submitted a request, so an audit row can say "this came from the reporting service" rather than only "a Java HTTP client". This is for identification and audit only: it never grants or blocks access.
application_name, set onPOST /me/api-keysand the service-account issue/rotate endpoints. A rotation inherits the old key's name unless a new one is given. The name cannot be forged without the key, and it always takes precedence over the header.X-AccessFlow-Applicationrequest header is used when the key has no name or the caller signs in with a JWT. The caller controls it, so it is recorded with sourceHEADERand labelled Untrusted in the UI. The value is trimmed and dropped if it contains control characters. It is cut to 100 code points, so a two-part character like an emoji is never split.query_requestsasapplication_name+application_name_source(V189). It is set by all four submission paths: REST submit, break-glass, replay and MCPsubmit_query. Recurring runs copy it from their series.security.internal.ApplicationAuditMetadataContributor.audit_loggets no new column, because adding one would change the hash-chain input for every existing row (same approach as V176). This is also why other request types, such as API calls and deployments, can be filtered on the audit log without a column of their own.application_nameonGET /queries(and its CSV export),applicationNameonGET /admin/audit-log(and its CSV export). The export's own audit row records the filter asfilter_application_name, so it does not claim the exporter's application.application_name/application_name_sourceare now top-level fields in the canonical event (Splunk / HTTPS batch / S3) and appear ascs5/cs6in CEF. The docs note these two fields are copied from metadata and are not part of the hash-chain input.ClientApplicationTagshows the name, with an Untrusted tag for header values. It appears on query detail and on audit rows and the audit detail drawer.docs/07-security.mdrecords that any future operand must fail closed on a header source, likecicd_origindoes.Docs / website updated
docs/03-data-model.md,docs/04-api-spec.md,docs/05-backend.md,docs/06-frontend.md,docs/07-security.md,docs/13-mcp.mdREADME.md(audit log feature line)website/docs/configuration/audit-compliance/index.html: new Which application made a request? subsection (#cfg-audit-application), the filter list and the sinks sentencewebsite/docs/configuration/users-roles/index.html: service-account issue/rotate stepswebsite/README.md: content-source map rowhelp-corpus/regenerateddocs/09-deployment.md: no change, since no configuration setting was addedVerification
mvn clean verify -Pcoverageon the final tree: 10,309 tests, 0 failures. IncludesApplicationModulesTest,ApiPackageDependencyTest,MessagesParityTest, Spotless and Checkstyle.test:coverage(2,640 tests; 94.6% lines / 87.7% branches) all pass. The last commit, a one-line CSS fix to the tag, was re-checked with lint, typecheck, build and the tag's own test; the full coverage suite was not re-run after it.profile-api-keys,admin-audit-log,query-listandservice-accountsran against the e2e stack rebuilt from the final backend: 21/21 passed.help-corpusdrift check and the website tests pass.Review notes
Independent reviewers ran before this PR. Fixed:
@Pattern("[^\\p{Cntrl}]*")(400 on violation, with a new i18n key in all locales), and the forms have a matching rule.DefaultQuerySubmissionService,DefaultBreakGlassService,DefaultQueryReplayServiceand MCPsubmitQuery. Truncation now counts code points. A blank export filter is no longer recorded.Still open:
(organization_id, application_name).query_requestshas noorganization_idcolumn (org is reached through the datasource), so the index is a partial one onapplication_namealone.QUERY_REVIEW_REQUESTEDwhen AI analysis is off, do carry it. This matches how the V176 on-behalf-of attribution works.ApiKeysSection› "commits an expiry chosen from the panel" is flaky onmaintoo (failed 1 of 4 baseline runs); it is not caused by this change.Screenshots