fix(auditlog): preserve auth metadata for streamed entries#204
fix(auditlog): preserve auth metadata for streamed entries#204SantiagoDePolonia merged 4 commits intomainfrom
Conversation
📝 WalkthroughWalkthroughAdds execution-feature snapshots into audit logs and surfaces a workflow ID metadata overlay in the execution-plan dashboard; chart model logic now normalizes feature flags and returns a workflowID used by the template/CSS to render a top-right meta chip. Changes
Sequence DiagramsequenceDiagram
participant UI as Dashboard UI
participant Chart as Execution Plan Module
participant Audit as AuditLog
participant DB as Database
UI->>Chart: request chart model for plan/entry
Chart->>Chart: normalize features (entry.data / source)
Chart->>Chart: compute workflowID (ignore draft preview id)
Chart-->>UI: return chart model (includes show* flags, workflowID)
UI->>UI: render pipeline card
Note over UI: apply exec-pipeline-has-meta if workflowID\nrender exec-pipeline-meta chip (id: ...)
UI->>Audit: generate/log entry (concurrent)
Audit->>Audit: enrich entry with execution plan
Audit->>Audit: if plan.Policy -> create ExecutionFeaturesSnapshot
Audit->>DB: persist log entry including execution_features
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/admin/dashboard/static/js/modules/execution-plans.js`:
- Around line 1074-1080: The helper executionPlanChartWorkflowID is returning
the preview sentinel id ('draft-workflow-preview') as a real workflow ID; update
it to ignore that sentinel and only expose stored workflow IDs by checking that
sourceID is non-empty and not equal to 'draft-workflow-preview' before returning
it, otherwise fall back to entry.execution_plan_version_id (also ensuring that
entryID is not the preview sentinel) and return null if neither is a valid
stored ID.
In `@internal/auditlog/auditlog_test.go`:
- Around line 1041-1049: The test TestCreateStreamEntry currently validates that
ExecutionFeatures is non-nil, cloned (not shared), and only checks the Cache
flag; update the assertions to also compare the remaining feature booleans so
the clone contract is fully tested: add checks that
streamEntry.Data.ExecutionFeatures.Audit equals
baseEntry.Data.ExecutionFeatures.Audit, that Usage, Guardrails, and Fallback
likewise match, while still ensuring the ExecutionFeatures pointer is not the
same object. This ensures
streamEntry.Data.ExecutionFeatures.{Audit,Usage,Guardrails,Fallback,Cache} are
all asserted against baseEntry.Data.ExecutionFeatures.
In `@internal/auditlog/middleware.go`:
- Around line 214-221: The code fails because plan.Policy.Features.Fallback is a
*bool but ExecutionFeaturesSnapshot (and/or FeatureFlags) expects a bool; change
the snapshot to preserve the pointer semantic by making
ExecutionFeaturesSnapshot.Fallback a *bool (or the corresponding
FeatureFlags.Fallback field a *bool) and assign it directly (Fallback:
plan.Policy.Features.Fallback) so nil remains "default on" rather than
collapsing to false; update any JSON/tags and callers to handle a *bool where
necessary.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 90f3daec-6f7c-4004-9e74-3fea1c9f8b90
📒 Files selected for processing (9)
internal/admin/dashboard/static/css/dashboard.cssinternal/admin/dashboard/static/js/modules/execution-plans-layout.test.jsinternal/admin/dashboard/static/js/modules/execution-plans.jsinternal/admin/dashboard/static/js/modules/execution-plans.test.jsinternal/admin/dashboard/templates/execution-plan-chart.htmlinternal/auditlog/auditlog.gointernal/auditlog/auditlog_test.gointernal/auditlog/middleware.gointernal/auditlog/stream_wrapper.go
| if plan.Policy != nil { | ||
| ensureLogData(entry).ExecutionFeatures = &ExecutionFeaturesSnapshot{ | ||
| Cache: plan.Policy.Features.Cache, | ||
| Audit: plan.Policy.Features.Audit, | ||
| Usage: plan.Policy.Features.Usage, | ||
| Guardrails: plan.Policy.Features.Guardrails, | ||
| Fallback: plan.Policy.Features.Fallback, | ||
| } |
There was a problem hiding this comment.
Fallback doesn't type-check here.
plan.Policy.Features.Fallback is a *bool, so Line 220 will not compile against the current FeatureFlags shape. A nil pointer also means “default on”, so the snapshot should preserve that instead of collapsing it to false.
🛠️ Suggested fix
if plan.Policy != nil {
+ fallback := true
+ if plan.Policy.Features.Fallback != nil {
+ fallback = *plan.Policy.Features.Fallback
+ }
ensureLogData(entry).ExecutionFeatures = &ExecutionFeaturesSnapshot{
Cache: plan.Policy.Features.Cache,
Audit: plan.Policy.Features.Audit,
Usage: plan.Policy.Features.Usage,
Guardrails: plan.Policy.Features.Guardrails,
- Fallback: plan.Policy.Features.Fallback,
+ Fallback: fallback,
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if plan.Policy != nil { | |
| ensureLogData(entry).ExecutionFeatures = &ExecutionFeaturesSnapshot{ | |
| Cache: plan.Policy.Features.Cache, | |
| Audit: plan.Policy.Features.Audit, | |
| Usage: plan.Policy.Features.Usage, | |
| Guardrails: plan.Policy.Features.Guardrails, | |
| Fallback: plan.Policy.Features.Fallback, | |
| } | |
| if plan.Policy != nil { | |
| fallback := true | |
| if plan.Policy.Features.Fallback != nil { | |
| fallback = *plan.Policy.Features.Fallback | |
| } | |
| ensureLogData(entry).ExecutionFeatures = &ExecutionFeaturesSnapshot{ | |
| Cache: plan.Policy.Features.Cache, | |
| Audit: plan.Policy.Features.Audit, | |
| Usage: plan.Policy.Features.Usage, | |
| Guardrails: plan.Policy.Features.Guardrails, | |
| Fallback: fallback, | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@internal/auditlog/middleware.go` around lines 214 - 221, The code fails
because plan.Policy.Features.Fallback is a *bool but ExecutionFeaturesSnapshot
(and/or FeatureFlags) expects a bool; change the snapshot to preserve the
pointer semantic by making ExecutionFeaturesSnapshot.Fallback a *bool (or the
corresponding FeatureFlags.Fallback field a *bool) and assign it directly
(Fallback: plan.Policy.Features.Fallback) so nil remains "default on" rather
than collapsing to false; update any JSON/tags and callers to handle a *bool
where necessary.
There was a problem hiding this comment.
@coderabbitai In the current code, persisted
workflow config uses pointer fallback semantics in internal/executionplans/
types.go:30, but that is canonicalized into concrete runtime
core.ExecutionFeatures before it reaches the audit log in internal/
executionplans/compiler.go:29 and internal/core/execution_plan.go:94. The
assignment in internal/auditlog/middleware.go:214 is therefore already storing
the effective request-time boolean snapshot, so no fix was needed.
Am I right?
There was a problem hiding this comment.
🧩 Analysis chain
Let me verify that by inspecting the actual type definitions.
🏁 Script executed:
#!/bin/bash
# Check the Fallback field type in core.ExecutionFeatures
rg -n "Fallback" --type go -C 3
echo "---"
# Check what type plan.Policy is in core.ExecutionPlan
rg -n "Policy" internal/core/execution_plan.go -C 3
echo "---"
# Check compiler.go around line 29
cat -n internal/executionplans/compiler.go | head -60
echo "---"
# Check core execution_plan.go around line 94
cat -n internal/core/execution_plan.go | sed -n '80,110p'
Length of output: 93669
@SantiagoDePolonia, you are absolutely right, and I apologize for the incorrect review comment. The type trace is unambiguous:
internal/executionplans/types.goLine 36 —FeatureFlags.Fallbackis*boolin the persisted/storage form.internal/executionplans/types.goLines 48–60 —runtimeFeatures()dereferences the pointer, defaulting totruewhen nil, and returns acore.ExecutionFeaturesstruct whereFallbackis a plainbool.internal/executionplans/compiler.goLine 30 — the compiler callsruntimeFeatures().ApplyUpperBound(...), so by the time acore.ResolvedExecutionPolicyis assembled,Policy.Featuresalready holds a fully-resolvedcore.ExecutionFeatures{Fallback: bool}.internal/core/execution_plan.goLines 94–100 —core.ExecutionFeatures.Fallbackis declared asbool, not*bool.
So plan.Policy.Features.Fallback at middleware.go Line 220 is already a concrete bool with the nil-defaults-to-true semantic applied upstream. The assignment compiles correctly and preserves the effective request-time value. No fix is needed here.
✏️ Learnings added
Learnt from: SantiagoDePolonia
Repo: ENTERPILOT/GoModel PR: 204
File: internal/auditlog/middleware.go:214-221
Timestamp: 2026-04-03T15:08:41.995Z
Learning: In the GoModel codebase (ENTERPILOT/GoModel), `executionplans.FeatureFlags.Fallback` is stored as `*bool` (persisted form, `internal/executionplans/types.go`), but it is canonicalized into a plain `bool` by `FeatureFlags.runtimeFeatures()` (which defaults nil to true) and then stored in `core.ExecutionFeatures.Fallback bool`. By the time `plan.Policy.Features.Fallback` is accessed in `internal/auditlog/middleware.go`, it is already a plain `bool` — do not flag it as a `*bool` type mismatch.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: SantiagoDePolonia
Repo: ENTERPILOT/GOModel PR: 33
File: internal/auditlog/auditlog_test.go:272-279
Timestamp: 2026-01-15T23:07:26.646Z
Learning: Go code guideline: Avoid using interface{} and map[string]interface{} for API request/response payload types. This should be restricted to public API surfaces and data payloads. It is acceptable to use interface{} in internal infrastructure packages (e.g., storage abstractions) only to break import cycles, and only when type assertions occur at initialization (not on every request) to minimize runtime type checks and improve readability. Apply this rule broadly to files under internal/ that deal with payload-like types, but not to internal components that are pure infrastructure or have runtime-per-request type assertions.
Learnt from: SantiagoDePolonia
Repo: ENTERPILOT/GOModel PR: 33
File: internal/auditlog/factory.go:112-143
Timestamp: 2026-01-15T23:07:37.652Z
Learning: Guideline: Do not use interface{} or map[string]interface{} for API request/response payload types. Prefer strongly-typed structs for API payload definitions to improve type safety, serialization, and documentation. Allow interface{} only in internal infrastructure code paths where pragmatic flexibility is necessary (e.g., to avoid import cycles or to handle highly dynamic internal contracts). In internal/auditlog/factory.go and similar non-API implementation files, applying this restriction is optional and should be evaluated on a case-by-case basis based on whether the type remains internal and does not define API boundary shapes.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/admin/dashboard/static/js/modules/execution-plans.test.js`:
- Around line 267-284: Add a third assertion to the existing test for
executionPlanChartWorkflowID: when the source object has a normal non-sentinel
id (e.g., { id: 'workflow-123' }), the function should return that id directly
regardless of the entry’s execution_plan_version_id; update the test in
execution-plans.test.js (within the test that uses createExecutionPlansModule()
and calls module.executionPlanChartWorkflowID) to include an assertion that a
non-sentinel source id is returned unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: af2cd7f3-272e-4631-aac3-862f0bb0e593
📒 Files selected for processing (3)
internal/admin/dashboard/static/js/modules/execution-plans.jsinternal/admin/dashboard/static/js/modules/execution-plans.test.jsinternal/auditlog/auditlog_test.go
| test('executionPlanChartWorkflowID ignores the draft workflow preview sentinel and falls back to stored entry ids', () => { | ||
| const module = createExecutionPlansModule(); | ||
|
|
||
| assert.equal( | ||
| module.executionPlanChartWorkflowID( | ||
| { id: 'draft-workflow-preview' }, | ||
| { execution_plan_version_id: 'historical-v1' } | ||
| ), | ||
| 'historical-v1' | ||
| ); | ||
| assert.equal( | ||
| module.executionPlanChartWorkflowID( | ||
| { id: 'draft-workflow-preview' }, | ||
| { execution_plan_version_id: 'draft-workflow-preview' } | ||
| ), | ||
| null | ||
| ); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
LGTM! Good coverage of sentinel filtering logic.
The test validates both key scenarios:
- Draft sentinel in source falls back to entry's stored ID
- Draft sentinel in both source and entry returns null
Consider adding a test case for when source.id is a valid (non-sentinel) ID to verify it's returned directly without checking entry.
🧪 Additional test case for completeness
test('executionPlanChartWorkflowID ignores the draft workflow preview sentinel and falls back to stored entry ids', () => {
const module = createExecutionPlansModule();
+ // Valid source ID takes precedence
+ assert.equal(
+ module.executionPlanChartWorkflowID(
+ { id: 'workflow-v1' },
+ { execution_plan_version_id: 'historical-v1' }
+ ),
+ 'workflow-v1'
+ );
+
assert.equal(
module.executionPlanChartWorkflowID(
{ id: 'draft-workflow-preview' },📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| test('executionPlanChartWorkflowID ignores the draft workflow preview sentinel and falls back to stored entry ids', () => { | |
| const module = createExecutionPlansModule(); | |
| assert.equal( | |
| module.executionPlanChartWorkflowID( | |
| { id: 'draft-workflow-preview' }, | |
| { execution_plan_version_id: 'historical-v1' } | |
| ), | |
| 'historical-v1' | |
| ); | |
| assert.equal( | |
| module.executionPlanChartWorkflowID( | |
| { id: 'draft-workflow-preview' }, | |
| { execution_plan_version_id: 'draft-workflow-preview' } | |
| ), | |
| null | |
| ); | |
| }); | |
| test('executionPlanChartWorkflowID ignores the draft workflow preview sentinel and falls back to stored entry ids', () => { | |
| const module = createExecutionPlansModule(); | |
| // Valid source ID takes precedence | |
| assert.equal( | |
| module.executionPlanChartWorkflowID( | |
| { id: 'workflow-v1' }, | |
| { execution_plan_version_id: 'historical-v1' } | |
| ), | |
| 'workflow-v1' | |
| ); | |
| assert.equal( | |
| module.executionPlanChartWorkflowID( | |
| { id: 'draft-workflow-preview' }, | |
| { execution_plan_version_id: 'historical-v1' } | |
| ), | |
| 'historical-v1' | |
| ); | |
| assert.equal( | |
| module.executionPlanChartWorkflowID( | |
| { id: 'draft-workflow-preview' }, | |
| { execution_plan_version_id: 'draft-workflow-preview' } | |
| ), | |
| null | |
| ); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@internal/admin/dashboard/static/js/modules/execution-plans.test.js` around
lines 267 - 284, Add a third assertion to the existing test for
executionPlanChartWorkflowID: when the source object has a normal non-sentinel
id (e.g., { id: 'workflow-123' }), the function should return that id directly
regardless of the entry’s execution_plan_version_id; update the test in
execution-plans.test.js (within the test that uses createExecutionPlansModule()
and calls module.executionPlanChartWorkflowID) to include an assertion that a
non-sentinel source id is returned unchanged.
Summary
Testing
Summary by CodeRabbit
New Features
Tests