Keep vault roots off ./data/dev and reject unknown types or sensitive payloads before staging. Co-authored-by: Cursor <cursoragent@cursor.com>
212 lines
6.8 KiB
Go
212 lines
6.8 KiB
Go
package artifactvault
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// EnumerateTerminals lists only immutable ledger / completed-turn facts. Workspace paths are forbidden.
|
|
func EnumerateTerminals(ctx context.Context, pool *pgxpool.Pool, env string) ([]TerminalRow, error) {
|
|
if pool == nil {
|
|
return nil, fmt.Errorf("artifactvault: no database")
|
|
}
|
|
var rows []TerminalRow
|
|
approved, err := enumerateApproved(ctx, pool, env)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rows = append(rows, approved...)
|
|
commits, err := enumerateAgentCommits(ctx, pool, env)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rows = append(rows, commits...)
|
|
sealed, err := enumerateSealed(ctx, pool, env)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rows = append(rows, sealed...)
|
|
replies, err := enumerateAssistant(ctx, pool, env)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rows = append(rows, replies...)
|
|
return rows, nil
|
|
}
|
|
|
|
func LoadExclusions(ctx context.Context, pool *pgxpool.Pool) (map[string]string, error) {
|
|
out := map[string]string{}
|
|
if pool == nil {
|
|
return out, nil
|
|
}
|
|
q, err := pool.Query(ctx, `SELECT logical_resource_id, reason FROM artifact_backfill_exclusions WHERE expires_at > now()`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer q.Close()
|
|
for q.Next() {
|
|
var id, reason string
|
|
if err := q.Scan(&id, &reason); err != nil {
|
|
return nil, err
|
|
}
|
|
out[id] = reason
|
|
}
|
|
return out, q.Err()
|
|
}
|
|
|
|
func enumerateApproved(ctx context.Context, pool *pgxpool.Pool, env string) ([]TerminalRow, error) {
|
|
q, err := pool.Query(ctx, `
|
|
SELECT d.doc_id, d.project_id, d.review_snapshot_id, d.approved_at, COALESCE(b.content_markdown,'')
|
|
FROM document_records d
|
|
LEFT JOIN document_snapshots s ON s.id = d.review_snapshot_id
|
|
LEFT JOIN document_content_blobs b ON b.content_sha256 = s.content_sha256
|
|
WHERE d.current_state = 'approved' AND d.approved_at IS NOT NULL`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer q.Close()
|
|
var out []TerminalRow
|
|
for q.Next() {
|
|
var docID string
|
|
var projectID, snapID int64
|
|
var approvedAt *time.Time
|
|
var md string
|
|
if err := q.Scan(&docID, &projectID, &snapID, &approvedAt, &md); err != nil {
|
|
return nil, err
|
|
}
|
|
row := TerminalRow{
|
|
Facts: ApprovedFacts("approved", approvedAt, snapID),
|
|
Request: PublishRequest{
|
|
ArtifactType: TypeApprovedDocument, Environment: env, ProjectID: projectID,
|
|
ProjectExternalKey: ProjectKeyFromID(projectID), LogicalResourceID: docID,
|
|
SourceEventKind: "approved", SourceEventID: fmt.Sprintf("approved:%s:%d", docID, snapID),
|
|
SourceSnapshotID: snapID, Payload: []byte(md), TerminalState: "approved",
|
|
},
|
|
}
|
|
if snapID <= 0 || md == "" {
|
|
row.MissingEvidence = true
|
|
row.Reason = "missing_review_snapshot"
|
|
}
|
|
out = append(out, row)
|
|
}
|
|
return out, q.Err()
|
|
}
|
|
|
|
func enumerateAgentCommits(ctx context.Context, pool *pgxpool.Pool, env string) ([]TerminalRow, error) {
|
|
q, err := pool.Query(ctx, `
|
|
SELECT e.doc_id, e.id, e.to_snapshot_id, COALESCE(r.project_id,0), COALESCE(b.content_markdown,'')
|
|
FROM document_change_events e
|
|
LEFT JOIN document_records r ON r.doc_id = e.doc_id
|
|
LEFT JOIN document_snapshots s ON s.id = e.to_snapshot_id
|
|
LEFT JOIN document_content_blobs b ON b.content_sha256 = s.content_sha256
|
|
WHERE e.change_kind = 'agent_commit'`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer q.Close()
|
|
var out []TerminalRow
|
|
for q.Next() {
|
|
var docID string
|
|
var eventID, snapID, projectID int64
|
|
var md string
|
|
if err := q.Scan(&docID, &eventID, &snapID, &projectID, &md); err != nil {
|
|
return nil, err
|
|
}
|
|
row := TerminalRow{
|
|
Facts: AgentCommitFacts(snapID),
|
|
Request: PublishRequest{
|
|
ArtifactType: TypeAgentCommit, Environment: env, ProjectID: projectID,
|
|
ProjectExternalKey: ProjectKeyFromID(projectID), LogicalResourceID: docID,
|
|
SourceEventKind: "agent_commit", SourceEventID: fmt.Sprintf("ev:%d", eventID),
|
|
SourceSnapshotID: snapID, Payload: []byte(md), TerminalState: "committed",
|
|
},
|
|
}
|
|
if snapID <= 0 || md == "" {
|
|
row.MissingEvidence = true
|
|
row.Reason = "missing_commit_snapshot"
|
|
}
|
|
out = append(out, row)
|
|
}
|
|
return out, q.Err()
|
|
}
|
|
|
|
func enumerateSealed(ctx context.Context, pool *pgxpool.Pool, env string) ([]TerminalRow, error) {
|
|
q, err := pool.Query(ctx, `
|
|
SELECT v.doc_id, v.id, v.head_snapshot_id, v.sealed_at, COALESCE(r.project_id,0), COALESCE(b.content_markdown,'')
|
|
FROM document_versions v
|
|
LEFT JOIN document_records r ON r.doc_id = v.doc_id
|
|
LEFT JOIN document_snapshots s ON s.id = v.head_snapshot_id
|
|
LEFT JOIN document_content_blobs b ON b.content_sha256 = s.content_sha256
|
|
WHERE v.status = 'sealed' AND v.sealed_at IS NOT NULL`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer q.Close()
|
|
var out []TerminalRow
|
|
for q.Next() {
|
|
var docID string
|
|
var verID, snapID, projectID int64
|
|
var sealedAt *time.Time
|
|
var md string
|
|
if err := q.Scan(&docID, &verID, &snapID, &sealedAt, &projectID, &md); err != nil {
|
|
return nil, err
|
|
}
|
|
row := TerminalRow{
|
|
Facts: SealedFacts(sealedAt, snapID),
|
|
Request: PublishRequest{
|
|
ArtifactType: TypeSealedVersion, Environment: env, ProjectID: projectID,
|
|
ProjectExternalKey: ProjectKeyFromID(projectID), LogicalResourceID: fmt.Sprintf("%s:v%d", docID, verID),
|
|
SourceEventKind: "version_sealed", SourceEventID: fmt.Sprintf("ver:%d", verID),
|
|
SourceSnapshotID: snapID, Payload: []byte(md), TerminalState: "sealed",
|
|
},
|
|
}
|
|
if snapID <= 0 || md == "" {
|
|
row.MissingEvidence = true
|
|
row.Reason = "missing_sealed_head"
|
|
}
|
|
out = append(out, row)
|
|
}
|
|
return out, q.Err()
|
|
}
|
|
|
|
func enumerateAssistant(ctx context.Context, pool *pgxpool.Pool, env string) ([]TerminalRow, error) {
|
|
q, err := pool.Query(ctx, `
|
|
SELECT t.session_id, t.client_turn_id, t.assistant_message_id, t.completed_at, t.project_id,
|
|
COALESCE(m.content,''), COALESCE(m.export_policy,'none')
|
|
FROM chat_turns t
|
|
LEFT JOIN chat_messages m ON m.id = t.assistant_message_id
|
|
WHERE t.status = 'completed' AND t.completed_at IS NOT NULL`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer q.Close()
|
|
var out []TerminalRow
|
|
for q.Next() {
|
|
var sessionID, clientTurnID, content, policy string
|
|
var msgID, projectID int64
|
|
var completedAt *time.Time
|
|
if err := q.Scan(&sessionID, &clientTurnID, &msgID, &completedAt, &projectID, &content, &policy); err != nil {
|
|
return nil, err
|
|
}
|
|
logical := fmt.Sprintf("msg:%d", msgID)
|
|
row := TerminalRow{
|
|
Facts: AssistantFacts("completed", completedAt, msgID, policy),
|
|
Request: PublishRequest{
|
|
ArtifactType: TypeAssistantReply, Environment: env, ProjectID: projectID,
|
|
ProjectExternalKey: ProjectKeyFromID(projectID), LogicalResourceID: logical,
|
|
SourceEventKind: "assistant_completed", SourceEventID: sessionID + ":" + clientTurnID,
|
|
SourceMessageID: msgID, Payload: []byte(content), TerminalState: "completed",
|
|
},
|
|
}
|
|
if msgID <= 0 || content == "" {
|
|
row.MissingEvidence = true
|
|
row.Reason = "missing_completed_body"
|
|
}
|
|
out = append(out, row)
|
|
}
|
|
return out, q.Err()
|
|
}
|