mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
feat: populate CI invocation context on cloud events (#304)
* feat: add CloudSinkEnvResolver interface with default implementation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add GitHub Actions environment resolver for cloud sink Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: populate invocation context with CI environment on cloud events Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address lint errors in cloud sink tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: use getter-based CloudSinkCIResolver with nil-when-no-CI Rename to CloudSinkCIResolver with focused CI concern. Factory returns nil when no CI is detected, removing the need for IsCI() and a default resolver. Leaves room for a separate agent resolver in the future. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add CI metadata support using updated API SDK Update SDK to include SetMetadata on EndpointCIContext. Add Metadata() to CloudSinkCIResolver interface and GitHub Actions implementation (workflow, job, run_attempt, server_url). Wire metadata into buildInvocationContext. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: address review comments on CI resolver - Inject CloudSinkCIResolver as dependency into newCloudSink for testability - Check both GITHUB_ACTIONS and GITHUB_RUN_ID for GHA environment detection - Make factory and constructor package-private (newCloudSinkCIResolver, newGithubActionsCIResolver) - Attach invocation context only to session complete events, not every event Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: fail fast on os.Getwd error instead of swallowing it Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
4540dafccc
commit
6087bc922f
@@ -40,6 +40,7 @@ func newTestCloudSink(t *testing.T, transport endpointsync.EventTransport) *clou
|
||||
return &cloudSink{
|
||||
SyncClientBundle: &SyncClientBundle{syncClient: syncClient},
|
||||
invocationID: "test-invocation",
|
||||
workingDir: t.TempDir(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,3 +99,59 @@ func TestCloudSinkEmitAndSync(t *testing.T) {
|
||||
assert.Equal(t, 1, synced)
|
||||
assert.Equal(t, 1, len(transport.requests))
|
||||
}
|
||||
|
||||
func TestCloudSinkSetsInvocationContextOnSessionComplete(t *testing.T) {
|
||||
transport := &mockTransport{}
|
||||
|
||||
sink := newTestCloudSink(t, transport)
|
||||
defer func() {
|
||||
require.NoError(t, sink.Close())
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
err := sink.Handle(ctx, AuditEvent{
|
||||
Type: EventTypeInstallStarted,
|
||||
Timestamp: time.Now(),
|
||||
PackageManager: "npm",
|
||||
Args: []string{"install", "express"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = sink.Handle(ctx, AuditEvent{
|
||||
Type: EventTypeMalwareBlocked,
|
||||
Timestamp: time.Now(),
|
||||
Message: "blocked malware package",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = sink.Handle(ctx, AuditEvent{
|
||||
Type: EventTypeSessionComplete,
|
||||
Timestamp: time.Now(),
|
||||
SessionData: &SessionData{
|
||||
PackageManager: "npm",
|
||||
FlowType: FlowTypeGuard,
|
||||
Outcome: OutcomeSuccess,
|
||||
TotalAnalyzed: 1,
|
||||
AllowedCount: 1,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
synced, err := sink.syncClient.Sync(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, synced)
|
||||
require.Equal(t, 1, len(transport.requests))
|
||||
|
||||
events := transport.requests[0].GetEvents()
|
||||
require.Equal(t, 2, len(events))
|
||||
|
||||
malwareEvent := events[0]
|
||||
assert.Nil(t, malwareEvent.GetInvocationContext(), "non-session events should not have invocation context")
|
||||
|
||||
sessionEvent := events[1]
|
||||
invCtx := sessionEvent.GetInvocationContext()
|
||||
require.NotNil(t, invCtx, "session complete event must have invocation context")
|
||||
assert.Contains(t, invCtx.GetCommand(), "npm")
|
||||
assert.NotEmpty(t, invCtx.GetWorkingDirectory())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user