fix(multi-tenancy): scope inject listings so inject_type resolves (#7605) - #7652
Conversation
) The inject read and single-inject mutation endpoints were @transactional without a TxCtx parameter, so app.current_tenants was never set and can_access_tenant fails closed on the v2-scoped injectors table. Inject#getType() and the inject_type criteria selection both resolve the injector through that table, so they returned null and the frontend drew the generic "unknown" icon on the execution screens.
|
📖 Documentation check — ✅ Passed 2 functional file(s), 0 doc file(s) changed. No documentation gaps detected. |
There was a problem hiding this comment.
Pull request overview
This PR addresses a multi-tenancy v2 scoping regression where inject listings/mutations could serialize inject_type as null (causing the frontend to show the “unknown” icon) because app.current_tenants wasn’t set for the transaction, making can_access_tenant fail closed on the v2-scoped injectors table.
Changes:
- Add a
TxCtxcontroller parameter to multiple simulation/scenario inject read endpoints and inject mutations that return anInject, ensuring v2 tenant scope is established for serialization paths. - Register those entrypoints in
TenantScopedEntrypointsTxCtxArchTestto prevent future accidental removal of the requiredTxCtxparameter.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| openaev-api/src/main/java/io/openaev/rest/inject/SimulationInjectApi.java | Adds TxCtx to inject listing/search/results and inject mutation endpoints so v2 tenant scope is set for injector resolution. |
| openaev-api/src/main/java/io/openaev/rest/inject/ScenarioInjectApi.java | Adds TxCtx to scenario inject listing/single read and activation mutation so injector resolution remains tenant-scoped. |
| openaev-api/src/test/java/io/openaev/architecture/TenantScopedEntrypointsTxCtxArchTest.java | Extends the ArchUnit guard list to enforce TxCtx presence on the affected entrypoints. |
Suppressed comments (2)
openaev-api/src/main/java/io/openaev/rest/inject/ScenarioInjectApi.java:131
- issue (blocking): scenarioInject validates the scenario but then loads the inject with findById(injectId) without scoping it to the scenarioId. With
@AccessControlkeyed on scenarioId, this can allow reading an inject that belongs to another scenario (within the same tenant) if its id is known. Fetch the inject via a scenario-scoped query (or delegate to ScenarioInjectService#findInjectForScenario).
Scenario scenario = this.scenarioService.scenario(scenarioId);
assert scenarioId.equals(scenario.getId());
return injectRepository.findById(injectId).orElseThrow(ElementNotFoundException::new);
openaev-api/src/main/java/io/openaev/rest/inject/ScenarioInjectApi.java:127
- suggestion (non-blocking): this is a read-only endpoint; switching the surrounding transaction to transactional(readOnly = true) avoids unnecessary dirty-checking overhead (the current annotation above the mapping is read/write).
public Inject scenarioInject(
TxCtx ctx,
@PathVariable @NotBlank final String scenarioId,
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| public Iterable<Inject> exerciseInjects( | ||
| TxCtx ctx, @PathVariable @NotBlank final String exerciseId) { |
| public Iterable<Inject> scenarioInjects( | ||
| TxCtx ctx, @PathVariable @NotBlank final String scenarioId) { |
Proposed changes
TxCtxparameter to the inject read endpoints (exerciseInjects,exerciseInjectsSimple,searchExerciseInjects,exerciseInjectsResults,scenarioInjects,scenarioInject,scenarioInjectsSimple) and to the single-inject mutations that return anInject(activation, trigger, status, teams). Without it the transaction never setsapp.current_tenants, socan_access_tenantfails closed on the v2-scopedinjectorstable:Inject#getType()and theinject_typecriteria selection both resolve the injector through that table and came backnull, which the frontend renders as the generic "unknown" icon.TenantScopedEntrypointsTxCtxArchTestso the parameter cannot be dropped again.Testing Instructions
Related issues
Checklist