@kici-dev/engine 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +1 -6
  3. package/dist/audit/access-log-policy.d.ts +97 -0
  4. package/dist/audit/access-log-policy.js +195 -0
  5. package/dist/audit/activity.d.ts +156 -0
  6. package/dist/audit/activity.js +175 -0
  7. package/dist/audit/retention-policy.d.ts +157 -0
  8. package/dist/audit/retention-policy.js +364 -0
  9. package/dist/bundler/index.d.ts +3 -0
  10. package/dist/bundler/index.js +3 -0
  11. package/dist/bundler/rolldown-config.d.ts +41 -0
  12. package/dist/bundler/rolldown-config.js +40 -0
  13. package/dist/chunk-gOLHoazu.js +4 -0
  14. package/dist/env/environment-allowlist.d.ts +45 -0
  15. package/dist/env/environment-allowlist.js +69 -0
  16. package/dist/environment/index.d.ts +3 -0
  17. package/dist/environment/index.js +3 -0
  18. package/dist/environment/scope-resolver.d.ts +35 -0
  19. package/dist/environment/scope-resolver.js +77 -0
  20. package/dist/environment/types.d.ts +98 -0
  21. package/dist/environment/types.js +2 -0
  22. package/dist/index.d.ts +54 -0
  23. package/dist/index.js +45 -0
  24. package/dist/labels.d.ts +106 -0
  25. package/dist/labels.js +162 -0
  26. package/dist/metrics/metric-catalog.generated.d.ts +400 -0
  27. package/dist/metrics/metric-catalog.generated.js +510 -0
  28. package/dist/protocol/dashboard-global-workflows.d.ts +9 -0
  29. package/dist/protocol/dashboard-global-workflows.js +3 -0
  30. package/dist/protocol/event-log-payload.d.ts +16 -0
  31. package/dist/protocol/event-log-payload.js +21 -0
  32. package/dist/protocol/messages/access-log.d.ts +545 -0
  33. package/dist/protocol/messages/access-log.js +175 -0
  34. package/dist/protocol/messages/actor.d.ts +100 -0
  35. package/dist/protocol/messages/actor.js +139 -0
  36. package/dist/protocol/messages/auth.d.ts +25 -0
  37. package/dist/protocol/messages/auth.js +36 -0
  38. package/dist/protocol/messages/browser.d.ts +369 -0
  39. package/dist/protocol/messages/browser.js +225 -0
  40. package/dist/protocol/messages/capabilities.d.ts +46 -0
  41. package/dist/protocol/messages/capabilities.js +42 -0
  42. package/dist/protocol/messages/common.d.ts +53 -0
  43. package/dist/protocol/messages/common.js +55 -0
  44. package/dist/protocol/messages/dashboard-global-workflows.d.ts +166 -0
  45. package/dist/protocol/messages/dashboard-global-workflows.js +80 -0
  46. package/dist/protocol/messages/dashboard.d.ts +4068 -0
  47. package/dist/protocol/messages/dashboard.js +1237 -0
  48. package/dist/protocol/messages/event-log.d.ts +49 -0
  49. package/dist/protocol/messages/event-log.js +45 -0
  50. package/dist/protocol/messages/execution-status.d.ts +164 -0
  51. package/dist/protocol/messages/execution-status.js +166 -0
  52. package/dist/protocol/messages/join.d.ts +18 -0
  53. package/dist/protocol/messages/join.js +28 -0
  54. package/dist/protocol/messages/log-pull.d.ts +27 -0
  55. package/dist/protocol/messages/log-pull.js +36 -0
  56. package/dist/protocol/messages/observe.d.ts +75 -0
  57. package/dist/protocol/messages/observe.js +70 -0
  58. package/dist/protocol/messages/orchestrator-agent.d.ts +606 -0
  59. package/dist/protocol/messages/orchestrator-agent.js +481 -0
  60. package/dist/protocol/messages/peer.d.ts +795 -0
  61. package/dist/protocol/messages/peer.js +372 -0
  62. package/dist/protocol/messages/platform-orchestrator.d.ts +1888 -0
  63. package/dist/protocol/messages/platform-orchestrator.js +379 -0
  64. package/dist/protocol/messages/run-events.d.ts +155 -0
  65. package/dist/protocol/messages/run-events.js +115 -0
  66. package/dist/protocol/messages/saas-orchestrator.d.ts +2179 -0
  67. package/dist/protocol/messages/source-registration.d.ts +103 -0
  68. package/dist/protocol/messages/source-registration.js +109 -0
  69. package/dist/protocol/messages/test-run.d.ts +59 -0
  70. package/dist/protocol/messages/test-run.js +52 -0
  71. package/dist/protocol/version.d.ts +12 -0
  72. package/dist/protocol/version.js +17 -0
  73. package/dist/provider/changed-files-fetcher.d.ts +24 -0
  74. package/dist/provider/changed-files-fetcher.js +2 -0
  75. package/dist/provider/check-run-conclusion.d.ts +15 -0
  76. package/dist/provider/check-run-conclusion.js +19 -0
  77. package/dist/provider/check-status-poster.d.ts +15 -0
  78. package/dist/provider/check-status-poster.js +2 -0
  79. package/dist/provider/clone-token-provider.d.ts +58 -0
  80. package/dist/provider/clone-token-provider.js +2 -0
  81. package/dist/provider/contributor-resolver.d.ts +22 -0
  82. package/dist/provider/contributor-resolver.js +2 -0
  83. package/dist/provider/index.d.ts +23 -0
  84. package/dist/provider/index.js +3 -0
  85. package/dist/provider/lock-file-fetcher.d.ts +24 -0
  86. package/dist/provider/lock-file-fetcher.js +2 -0
  87. package/dist/provider/repo-url-builder.d.ts +35 -0
  88. package/dist/provider/repo-url-builder.js +2 -0
  89. package/dist/provider/types.d.ts +9 -0
  90. package/dist/provider/types.js +2 -0
  91. package/dist/provider/webhook-normalizer.d.ts +163 -0
  92. package/dist/provider/webhook-normalizer.js +2 -0
  93. package/dist/registration/registerable-trigger-type.d.ts +52 -0
  94. package/dist/registration/registerable-trigger-type.js +56 -0
  95. package/dist/scaler/resource-types.d.ts +90 -0
  96. package/dist/scaler/resource-types.js +99 -0
  97. package/dist/scaler/scaler-backend-type.d.ts +16 -0
  98. package/dist/scaler/scaler-backend-type.js +20 -0
  99. package/dist/secrets/index.d.ts +7 -0
  100. package/dist/secrets/index.js +2 -0
  101. package/dist/secrets/types.d.ts +138 -0
  102. package/dist/secrets/types.js +2 -0
  103. package/dist/state-machine/index.d.ts +2 -0
  104. package/dist/state-machine/index.js +3 -0
  105. package/dist/state-machine/machine.d.ts +34 -0
  106. package/dist/state-machine/machine.js +103 -0
  107. package/dist/state-machine/types.d.ts +34 -0
  108. package/dist/state-machine/types.js +15 -0
  109. package/dist/trigger/decision-trace.d.ts +41 -0
  110. package/dist/trigger/decision-trace.js +30 -0
  111. package/dist/trigger/jsonpath-matcher.d.ts +27 -0
  112. package/dist/trigger/jsonpath-matcher.js +92 -0
  113. package/dist/trigger/matcher.d.ts +29 -0
  114. package/dist/trigger/matcher.js +704 -0
  115. package/dist/trigger/trigger-event-type.d.ts +14 -0
  116. package/dist/trigger/trigger-event-type.js +66 -0
  117. package/dist/trigger/types.d.ts +524 -0
  118. package/dist/trigger/types.js +48 -0
  119. package/dist/webhook/signature.d.ts +15 -0
  120. package/dist/webhook/signature.js +32 -0
  121. package/dist/ws/close-codes.d.ts +28 -0
  122. package/dist/ws/close-codes.js +33 -0
  123. package/dist/ws/rate-limiter.d.ts +86 -0
  124. package/dist/ws/rate-limiter.js +136 -0
  125. package/dist/ws/ws-like.d.ts +12 -0
  126. package/dist/ws/ws-like.js +2 -0
  127. package/package.json +54 -6
  128. package/sbom.spdx.json +202 -0
  129. package/index.js +0 -3
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Per-action warm-retention policy for the three audit-style tables:
3
+ * Platform `audit_log`, Orchestrator `access_log`, Orchestrator
4
+ * `secret_audit_log`.
5
+ *
6
+ * Single source of truth for "how long does a row stay in PG before being
7
+ * archived to cold storage." Mirrors the per-action sampling policy in
8
+ * `./access-log-policy.ts`; both modules classify by the same action
9
+ * dimension, just for different downstream decisions.
10
+ *
11
+ * The classification table came from research-doc §5
12
+ * and the user's
13
+ * `## Decisions` section. Two override layers apply uniformly:
14
+ *
15
+ * 1. `outcome` is `denied` or `error` → retain 180d (forensic value).
16
+ * 2. `actor.type === 'platform_operator'` → retain 365d
17
+ * (compliance — non-org-member break-glass).
18
+ *
19
+ * Override 1 wins over override 2 when both apply (more conservative).
20
+ *
21
+ * The SQL-fragment generators emit Postgres `CASE` expressions so the
22
+ * adapters can splice them directly into Kysely raw SQL without duplicating
23
+ * the classification logic. The strings produced are derived deterministically
24
+ * from the JS tables here, so editing the JS regenerates the SQL — and the
25
+ * `validateActionShape()` test guards against SQL-injection surface by
26
+ * asserting every action key matches `/^[a-z0-9_.-]+$/`.
27
+ *
28
+ * Browser-safe: this module MUST NOT import any Node built-ins. It is
29
+ * re-exported via the `@kici-dev/engine` barrel which the dashboard imports.
30
+ */
31
+ import { AccessLogAction, type AccessLogOutcome } from '../protocol/messages/access-log.js';
32
+ import { type ActorType } from '../protocol/messages/actor.js';
33
+ /**
34
+ * Warm-retention days per `AccessLogAction`. Exhaustive over the enum so a
35
+ * new action without an entry is a compile-time error.
36
+ *
37
+ * Buckets:
38
+ * - 30 days: high-volume reads (already sampled per `POLICY_BY_ACTION`),
39
+ * internal-ops reads (rate-limited, denied/error only at write time).
40
+ * - 180 days: sensitive reads + tenant-plane mutations.
41
+ * - 365 days: secret mutations / reveals + cold-store internals
42
+ * (compliance-class).
43
+ */
44
+ export declare const ACCESS_LOG_WARM_DAYS: Record<AccessLogAction, number>;
45
+ export declare function getAccessLogWarmDays(args: {
46
+ action: AccessLogAction;
47
+ outcome: AccessLogOutcome;
48
+ actorType: ActorType;
49
+ }): number;
50
+ /**
51
+ * Days a Platform `audit_log` row stays in PG before archival, ignoring
52
+ * actor-type overrides. Use `getAuditLogWarmDays()` to apply the override.
53
+ */
54
+ export declare function auditLogWarmDays(action: string): number;
55
+ export declare function getAuditLogWarmDays(args: {
56
+ action: string;
57
+ actorType: ActorType;
58
+ }): number;
59
+ export declare function secretAuditLogWarmDays(action: string): number;
60
+ export declare function getSecretAuditLogWarmDays(args: {
61
+ action: string;
62
+ outcome: 'allowed' | 'denied';
63
+ }): number;
64
+ /**
65
+ * Postgres CASE expression yielding the per-row warm-retention `INTERVAL`.
66
+ * Splice into a `sql.raw()` template inside the adapter:
67
+ *
68
+ * sql`WHERE created_at < (NOW() - (${sql.raw(accessLogWarmSqlCase())}))`
69
+ */
70
+ export declare function accessLogWarmSqlCase(): string;
71
+ /**
72
+ * Postgres CASE for Platform `audit_log`. Mirrors `auditLogWarmDays()`.
73
+ *
74
+ * The Platform `audit_log` table has neither an `outcome` nor an `actor_type`
75
+ * column (per migration `001_initial`). Actor type only exists in the JS
76
+ * application layer — when an actor is written, the JS code derives `actor_id`
77
+ * from `actor.sub` (or a fixed string like `'platform-admin-cli'`). Because of
78
+ * that, the SQL CASE here cannot apply the `actor.type='platform_operator'`
79
+ * override the way `accessLogWarmSqlCase()` does — the column doesn't exist.
80
+ *
81
+ * In practice this is fine: there is no Platform code path that writes a
82
+ * `platform_operator` actor into Platform `audit_log`. Platform-operator
83
+ * break-glass (`makePlatformOperatorActor`) is exclusively used to proxy
84
+ * orchestrator reads via the support-read listener; those rows land in the
85
+ * orchestrator's `access_log`, where the per-row CASE *can* see `actor_type`.
86
+ *
87
+ * The TS-side `getAuditLogWarmDays()` keeps the override defensively so any
88
+ * future call site that genuinely passes a `platform_operator` actor still
89
+ * gets the right TTL — just not the SQL pre-filter, which has no column to
90
+ * inspect.
91
+ */
92
+ export declare function auditLogWarmSqlCase(): string;
93
+ /**
94
+ * Postgres CASE for Orchestrator `secret_audit_log`. No `actor_type` column
95
+ * on this table; only the denied-outcome override applies.
96
+ */
97
+ export declare function secretAuditLogWarmSqlCase(): string;
98
+ /**
99
+ * Cold-store retention horizon. Number of days a chunk lives in S3 after
100
+ * archival before it is purged; `'forever'` means the chunk is never purged.
101
+ */
102
+ export type ColdRetention = number | 'forever';
103
+ /**
104
+ * Cold-retention days per `AccessLogAction`. Mirrors `ACCESS_LOG_WARM_DAYS`'s
105
+ * shape (exhaustive over the enum). Buckets:
106
+ *
107
+ * - 30 days: internal-ops reads (only denied/error rows survive write-time
108
+ * sampling; once they age out of warm, no need to keep them in cold either).
109
+ * - 180 days: high-volume tenant reads (sampled at write-time too — the
110
+ * forensic value drops sharply after 6 months of cold).
111
+ * - 730 days (2 years): sensitive reads + tenant-plane mutations
112
+ * (covers SOC 2 audit windows comfortably).
113
+ * - `'forever'`: secret mutations / reveals + cold-store internals
114
+ * (compliance-class — never purged).
115
+ */
116
+ export declare const ACCESS_LOG_COLD_DAYS: Record<AccessLogAction, ColdRetention>;
117
+ export declare function getAccessLogColdDays(args: {
118
+ action: AccessLogAction;
119
+ outcome: AccessLogOutcome;
120
+ actorType: ActorType;
121
+ }): ColdRetention;
122
+ /**
123
+ * Cold retention for Platform `audit_log`. Mirrors `auditLogWarmDays()`.
124
+ * Compliance-class actions (billing, RBAC, platform-admin, system events) are
125
+ * `'forever'`; everything else (tenant-plane mutations) is 730 days.
126
+ *
127
+ * Same column-availability caveat as `auditLogWarmSqlCase()` — Platform
128
+ * `audit_log` has no `outcome` or `actor_type` column; the JS-side override
129
+ * still applies for callers that genuinely have an `actorType` to pass.
130
+ */
131
+ export declare function auditLogColdDays(action: string): ColdRetention;
132
+ export declare function getAuditLogColdDays(args: {
133
+ action: string;
134
+ actorType: ActorType;
135
+ }): ColdRetention;
136
+ /**
137
+ * Cold retention for Orchestrator `secret_audit_log`. Sampled job-execution
138
+ * resolves are 180 days (already sampled at 1% in the writer + warm-retained
139
+ * 30d); everything else (mutations) is `'forever'`. The denied-outcome
140
+ * override promotes to 730 days.
141
+ */
142
+ export declare function secretAuditLogColdDays(action: string): ColdRetention;
143
+ export declare function getSecretAuditLogColdDays(args: {
144
+ action: string;
145
+ outcome: 'allowed' | 'denied';
146
+ }): ColdRetention;
147
+ /**
148
+ * Test-only helper that returns the minimum warm-retention TTL across all
149
+ * `AccessLogAction` actions and override paths. Used by adapter tests to
150
+ * sanity-check that `DEFAULT_CONFIG.warmTtlDays` matches this minimum (so
151
+ * the framework's partition-day scan doesn't pre-filter out rows the adapter
152
+ * would consider eligible).
153
+ */
154
+ export declare function minAccessLogWarmDays(): number;
155
+ export declare function minSecretAuditLogWarmDays(): number;
156
+ export declare function minAuditLogWarmDays(): number;
157
+ //# sourceMappingURL=retention-policy.d.ts.map
@@ -0,0 +1,364 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ //#region src/audit/retention-policy.ts
3
+ /**
4
+ * Warm-retention days per `AccessLogAction`. Exhaustive over the enum so a
5
+ * new action without an entry is a compile-time error.
6
+ *
7
+ * Buckets:
8
+ * - 30 days: high-volume reads (already sampled per `POLICY_BY_ACTION`),
9
+ * internal-ops reads (rate-limited, denied/error only at write time).
10
+ * - 180 days: sensitive reads + tenant-plane mutations.
11
+ * - 365 days: secret mutations / reveals + cold-store internals
12
+ * (compliance-class).
13
+ */
14
+ const ACCESS_LOG_WARM_DAYS = {
15
+ "run.detail.read": 30,
16
+ "run.orch_logs.read": 30,
17
+ "step.logs.read": 30,
18
+ "event_log.list.read": 30,
19
+ "environment.list.read": 30,
20
+ "environment.get.read": 30,
21
+ "environment.history.read": 30,
22
+ "registration.list.read": 30,
23
+ "global_workflows.get.read": 30,
24
+ "held_run.list.read": 30,
25
+ "env_binding.list.read": 30,
26
+ "backend.list.read": 30,
27
+ "backend.get.read": 30,
28
+ "diagnostics.read": 30,
29
+ "scaler.capacity.read": 30,
30
+ "scaler.agents.read": 30,
31
+ "event_log.detail.read": 180,
32
+ "event_log.payload.read": 180,
33
+ "run.payload.read": 180,
34
+ "env_var.list.read": 180,
35
+ "source_override.list.read": 180,
36
+ "access_log.list.read": 180,
37
+ "secret.list.read": 180,
38
+ "run.cancel": 180,
39
+ "run.rerun": 180,
40
+ "run.manual_schedule": 180,
41
+ "job.cancel": 180,
42
+ "environment.create": 180,
43
+ "environment.update": 180,
44
+ "environment.delete": 180,
45
+ "env_var.set": 180,
46
+ "env_var.delete": 180,
47
+ "source_override.set": 180,
48
+ "source_override.delete": 180,
49
+ "env_binding.set": 180,
50
+ "held_run.approve": 180,
51
+ "held_run.reject": 180,
52
+ "registration.disable": 180,
53
+ "registration.delete": 180,
54
+ "backend.sync": 180,
55
+ "backend.sync.one": 180,
56
+ "backend.test": 180,
57
+ "global_workflows.update": 180,
58
+ "event_dlq.list.read": 30,
59
+ "event_dlq.retry": 180,
60
+ "event_dlq.discard": 180,
61
+ "secret.set": 365,
62
+ "secret.delete": 365,
63
+ "secret.reveal": 365,
64
+ "secret_scope.create": 365,
65
+ "secret_scope.rename": 365,
66
+ "secret_scope.delete": 365,
67
+ archive_chunk: 365
68
+ };
69
+ /** Override outcomes that promote retention to 180 days regardless of action. */
70
+ const FORENSIC_OUTCOME_DAYS = 180;
71
+ /** Override actor type that promotes retention to 365 days. */
72
+ const PLATFORM_OPERATOR_DAYS = 365;
73
+ /**
74
+ * Default warm TTL for action strings outside `AccessLogAction.options`. Hit
75
+ * by E2E synthetic action names and would-be-future enum additions on a
76
+ * rolling deploy. Matches the conservative `180d` mutations bucket so
77
+ * unknown rows are never archived sooner than a tenant-plane mutation.
78
+ */
79
+ const UNKNOWN_ACTION_WARM_DAYS = 180;
80
+ function getAccessLogWarmDays(args) {
81
+ if (args.outcome !== "allowed") return FORENSIC_OUTCOME_DAYS;
82
+ if (args.actorType === "platform_operator") return PLATFORM_OPERATOR_DAYS;
83
+ return ACCESS_LOG_WARM_DAYS[args.action] ?? UNKNOWN_ACTION_WARM_DAYS;
84
+ }
85
+ /**
86
+ * Platform `audit_log.action` is a free-form string (no enum), so we classify
87
+ * by prefix / set membership. Compliance-class actions (billing, RBAC,
88
+ * platform-admin break-glass, system events) get 365 days; everything else
89
+ * defaults to 180 days (tenant-plane mutations).
90
+ *
91
+ * The Platform `audit_log` has no `outcome` column — every row is a "happened"
92
+ * event. The platform_operator override still applies via `actor_type`.
93
+ */
94
+ const COMPLIANCE_AUDIT_PREFIXES = [
95
+ "plan.",
96
+ "plan_config.",
97
+ "org.",
98
+ "member.",
99
+ "invite.",
100
+ "role.",
101
+ "platform-admin.",
102
+ "support-read."
103
+ ];
104
+ const COMPLIANCE_AUDIT_EXACT = new Set([
105
+ "archive_chunk",
106
+ "replay_chunk",
107
+ "scheduled_job_failure"
108
+ ]);
109
+ /**
110
+ * Days a Platform `audit_log` row stays in PG before archival, ignoring
111
+ * actor-type overrides. Use `getAuditLogWarmDays()` to apply the override.
112
+ */
113
+ function auditLogWarmDays(action) {
114
+ if (COMPLIANCE_AUDIT_EXACT.has(action)) return 365;
115
+ for (const prefix of COMPLIANCE_AUDIT_PREFIXES) if (action.startsWith(prefix)) return 365;
116
+ return 180;
117
+ }
118
+ function getAuditLogWarmDays(args) {
119
+ if (args.actorType === "platform_operator") return PLATFORM_OPERATOR_DAYS;
120
+ return auditLogWarmDays(args.action);
121
+ }
122
+ /**
123
+ * Orchestrator `secret_audit_log.action` is a free-form string (no enum).
124
+ * Sampled job-execution resolves are 30 days (already sampled at 1% in the
125
+ * writer per `shouldRecordSecretResolve`); everything else (mutations: set,
126
+ * delete, rotate, scope ops) is 365 days. The denied-outcome override
127
+ * promotes to 180 days. There is no `actor_type` column on this table, so
128
+ * the platform_operator override does not apply.
129
+ */
130
+ const SAMPLED_RESOLVE_ACTIONS = new Set(["resolve", "resolve_named"]);
131
+ function secretAuditLogWarmDays(action) {
132
+ if (SAMPLED_RESOLVE_ACTIONS.has(action)) return 30;
133
+ return 365;
134
+ }
135
+ function getSecretAuditLogWarmDays(args) {
136
+ if (args.outcome !== "allowed") return FORENSIC_OUTCOME_DAYS;
137
+ return secretAuditLogWarmDays(args.action);
138
+ }
139
+ /**
140
+ * Action strings that may appear in SQL must match this shape. A failed match
141
+ * means an action key was added that could escape the string-literal context
142
+ * — that's a bug, not user input, but we still reject it at test time.
143
+ */
144
+ const SAFE_ACTION_RE = /^[a-z0-9_.-]+$/;
145
+ function assertSafeAction(action) {
146
+ if (!SAFE_ACTION_RE.test(action)) throw new Error(`Unsafe action key for SQL: ${JSON.stringify(action)}`);
147
+ }
148
+ function quoteList(actions) {
149
+ for (const a of actions) assertSafeAction(a);
150
+ return actions.map((a) => `'${a}'`).join(",");
151
+ }
152
+ /**
153
+ * Group a `Record<action, days>` into `days → action[]` so the emitted CASE
154
+ * has one WHEN per distinct TTL value.
155
+ */
156
+ function groupByDays(map) {
157
+ const groups = /* @__PURE__ */ new Map();
158
+ for (const key of Object.keys(map)) {
159
+ const days = map[key];
160
+ const list = groups.get(days);
161
+ if (list) list.push(key);
162
+ else groups.set(days, [key]);
163
+ }
164
+ return groups;
165
+ }
166
+ /**
167
+ * Postgres CASE expression yielding the per-row warm-retention `INTERVAL`.
168
+ * Splice into a `sql.raw()` template inside the adapter:
169
+ *
170
+ * sql`WHERE created_at < (NOW() - (${sql.raw(accessLogWarmSqlCase())}))`
171
+ */
172
+ function accessLogWarmSqlCase() {
173
+ const groups = groupByDays(ACCESS_LOG_WARM_DAYS);
174
+ const sortedDays = [...groups.keys()].sort((a, b) => b - a);
175
+ const defaultDays = Math.min(...groups.keys());
176
+ const whenClauses = [];
177
+ whenClauses.push(`WHEN outcome IN ('denied','error') THEN INTERVAL '${FORENSIC_OUTCOME_DAYS} days'`);
178
+ whenClauses.push(`WHEN actor_type = 'platform_operator' THEN INTERVAL '${PLATFORM_OPERATOR_DAYS} days'`);
179
+ for (const days of sortedDays) {
180
+ if (days === defaultDays) continue;
181
+ const actions = groups.get(days);
182
+ whenClauses.push(`WHEN action IN (${quoteList(actions)}) THEN INTERVAL '${days} days'`);
183
+ }
184
+ return `CASE\n ${whenClauses.join("\n ")}\n ELSE INTERVAL '${defaultDays} days'\nEND`;
185
+ }
186
+ /**
187
+ * Postgres CASE for Platform `audit_log`. Mirrors `auditLogWarmDays()`.
188
+ *
189
+ * The Platform `audit_log` table has neither an `outcome` nor an `actor_type`
190
+ * column (per migration `001_initial`). Actor type only exists in the JS
191
+ * application layer — when an actor is written, the JS code derives `actor_id`
192
+ * from `actor.sub` (or a fixed string like `'platform-admin-cli'`). Because of
193
+ * that, the SQL CASE here cannot apply the `actor.type='platform_operator'`
194
+ * override the way `accessLogWarmSqlCase()` does — the column doesn't exist.
195
+ *
196
+ * In practice this is fine: there is no Platform code path that writes a
197
+ * `platform_operator` actor into Platform `audit_log`. Platform-operator
198
+ * break-glass (`makePlatformOperatorActor`) is exclusively used to proxy
199
+ * orchestrator reads via the support-read listener; those rows land in the
200
+ * orchestrator's `access_log`, where the per-row CASE *can* see `actor_type`.
201
+ *
202
+ * The TS-side `getAuditLogWarmDays()` keeps the override defensively so any
203
+ * future call site that genuinely passes a `platform_operator` actor still
204
+ * gets the right TTL — just not the SQL pre-filter, which has no column to
205
+ * inspect.
206
+ */
207
+ function auditLogWarmSqlCase() {
208
+ const exact = [...COMPLIANCE_AUDIT_EXACT];
209
+ const whenClauses = [];
210
+ const prefixPredicate = COMPLIANCE_AUDIT_PREFIXES.map((p) => {
211
+ assertSafeAction(p.replace(/\.$/, ""));
212
+ return `action LIKE '${p}%'`;
213
+ }).join(" OR ");
214
+ whenClauses.push(`WHEN ${prefixPredicate} THEN INTERVAL '365 days'`);
215
+ if (exact.length > 0) whenClauses.push(`WHEN action IN (${quoteList(exact)}) THEN INTERVAL '365 days'`);
216
+ return `CASE\n ${whenClauses.join("\n ")}\n ELSE INTERVAL '180 days'\nEND`;
217
+ }
218
+ /**
219
+ * Postgres CASE for Orchestrator `secret_audit_log`. No `actor_type` column
220
+ * on this table; only the denied-outcome override applies.
221
+ */
222
+ function secretAuditLogWarmSqlCase() {
223
+ const sampled = [...SAMPLED_RESOLVE_ACTIONS];
224
+ const whenClauses = [];
225
+ whenClauses.push(`WHEN outcome = 'denied' THEN INTERVAL '${FORENSIC_OUTCOME_DAYS} days'`);
226
+ if (sampled.length > 0) whenClauses.push(`WHEN action IN (${quoteList(sampled)}) THEN INTERVAL '30 days'`);
227
+ return `CASE\n ${whenClauses.join("\n ")}\n ELSE INTERVAL '365 days'\nEND`;
228
+ }
229
+ /**
230
+ * Cold-retention days per `AccessLogAction`. Mirrors `ACCESS_LOG_WARM_DAYS`'s
231
+ * shape (exhaustive over the enum). Buckets:
232
+ *
233
+ * - 30 days: internal-ops reads (only denied/error rows survive write-time
234
+ * sampling; once they age out of warm, no need to keep them in cold either).
235
+ * - 180 days: high-volume tenant reads (sampled at write-time too — the
236
+ * forensic value drops sharply after 6 months of cold).
237
+ * - 730 days (2 years): sensitive reads + tenant-plane mutations
238
+ * (covers SOC 2 audit windows comfortably).
239
+ * - `'forever'`: secret mutations / reveals + cold-store internals
240
+ * (compliance-class — never purged).
241
+ */
242
+ const ACCESS_LOG_COLD_DAYS = {
243
+ "run.detail.read": 180,
244
+ "run.orch_logs.read": 180,
245
+ "step.logs.read": 180,
246
+ "event_log.list.read": 180,
247
+ "environment.list.read": 180,
248
+ "environment.get.read": 180,
249
+ "environment.history.read": 180,
250
+ "registration.list.read": 180,
251
+ "global_workflows.get.read": 180,
252
+ "held_run.list.read": 180,
253
+ "env_binding.list.read": 180,
254
+ "backend.list.read": 180,
255
+ "backend.get.read": 180,
256
+ "diagnostics.read": 30,
257
+ "scaler.capacity.read": 30,
258
+ "scaler.agents.read": 30,
259
+ "event_log.detail.read": 730,
260
+ "event_log.payload.read": 730,
261
+ "run.payload.read": 730,
262
+ "env_var.list.read": 730,
263
+ "source_override.list.read": 730,
264
+ "access_log.list.read": 730,
265
+ "secret.list.read": 730,
266
+ "run.cancel": 730,
267
+ "run.rerun": 730,
268
+ "run.manual_schedule": 730,
269
+ "job.cancel": 730,
270
+ "environment.create": 730,
271
+ "environment.update": 730,
272
+ "environment.delete": 730,
273
+ "env_var.set": 730,
274
+ "env_var.delete": 730,
275
+ "source_override.set": 730,
276
+ "source_override.delete": 730,
277
+ "env_binding.set": 730,
278
+ "held_run.approve": 730,
279
+ "held_run.reject": 730,
280
+ "registration.disable": 730,
281
+ "registration.delete": 730,
282
+ "backend.sync": 730,
283
+ "backend.sync.one": 730,
284
+ "backend.test": 730,
285
+ "global_workflows.update": 730,
286
+ "event_dlq.list.read": 180,
287
+ "event_dlq.retry": 730,
288
+ "event_dlq.discard": 730,
289
+ "secret.set": "forever",
290
+ "secret.delete": "forever",
291
+ "secret.reveal": "forever",
292
+ "secret_scope.create": "forever",
293
+ "secret_scope.rename": "forever",
294
+ "secret_scope.delete": "forever",
295
+ archive_chunk: "forever"
296
+ };
297
+ /** Override outcome cold-retention (forensic — 2 years). */
298
+ const FORENSIC_OUTCOME_COLD_DAYS = 730;
299
+ /** Override actor type cold-retention (compliance — never purge). */
300
+ const PLATFORM_OPERATOR_COLD = "forever";
301
+ /**
302
+ * Default cold TTL for action strings outside `AccessLogAction.options`. Same
303
+ * conservative-by-default reasoning as `UNKNOWN_ACTION_WARM_DAYS`; matches
304
+ * the 730d "tenant-plane mutations" bucket so unknown rows are kept long
305
+ * enough for any forensic review.
306
+ */
307
+ const UNKNOWN_ACTION_COLD_DAYS = 730;
308
+ function getAccessLogColdDays(args) {
309
+ if (args.outcome !== "allowed") return FORENSIC_OUTCOME_COLD_DAYS;
310
+ if (args.actorType === "platform_operator") return PLATFORM_OPERATOR_COLD;
311
+ return ACCESS_LOG_COLD_DAYS[args.action] ?? UNKNOWN_ACTION_COLD_DAYS;
312
+ }
313
+ /**
314
+ * Cold retention for Platform `audit_log`. Mirrors `auditLogWarmDays()`.
315
+ * Compliance-class actions (billing, RBAC, platform-admin, system events) are
316
+ * `'forever'`; everything else (tenant-plane mutations) is 730 days.
317
+ *
318
+ * Same column-availability caveat as `auditLogWarmSqlCase()` — Platform
319
+ * `audit_log` has no `outcome` or `actor_type` column; the JS-side override
320
+ * still applies for callers that genuinely have an `actorType` to pass.
321
+ */
322
+ function auditLogColdDays(action) {
323
+ if (COMPLIANCE_AUDIT_EXACT.has(action)) return "forever";
324
+ for (const prefix of COMPLIANCE_AUDIT_PREFIXES) if (action.startsWith(prefix)) return "forever";
325
+ return 730;
326
+ }
327
+ function getAuditLogColdDays(args) {
328
+ if (args.actorType === "platform_operator") return PLATFORM_OPERATOR_COLD;
329
+ return auditLogColdDays(args.action);
330
+ }
331
+ /**
332
+ * Cold retention for Orchestrator `secret_audit_log`. Sampled job-execution
333
+ * resolves are 180 days (already sampled at 1% in the writer + warm-retained
334
+ * 30d); everything else (mutations) is `'forever'`. The denied-outcome
335
+ * override promotes to 730 days.
336
+ */
337
+ function secretAuditLogColdDays(action) {
338
+ if (SAMPLED_RESOLVE_ACTIONS.has(action)) return 180;
339
+ return "forever";
340
+ }
341
+ function getSecretAuditLogColdDays(args) {
342
+ if (args.outcome !== "allowed") return FORENSIC_OUTCOME_COLD_DAYS;
343
+ return secretAuditLogColdDays(args.action);
344
+ }
345
+ /**
346
+ * Test-only helper that returns the minimum warm-retention TTL across all
347
+ * `AccessLogAction` actions and override paths. Used by adapter tests to
348
+ * sanity-check that `DEFAULT_CONFIG.warmTtlDays` matches this minimum (so
349
+ * the framework's partition-day scan doesn't pre-filter out rows the adapter
350
+ * would consider eligible).
351
+ */
352
+ function minAccessLogWarmDays() {
353
+ return Math.min(...Object.values(ACCESS_LOG_WARM_DAYS));
354
+ }
355
+ function minSecretAuditLogWarmDays() {
356
+ return Math.min(30, FORENSIC_OUTCOME_DAYS);
357
+ }
358
+ function minAuditLogWarmDays() {
359
+ return 180;
360
+ }
361
+ //#endregion
362
+ export { ACCESS_LOG_COLD_DAYS, ACCESS_LOG_WARM_DAYS, accessLogWarmSqlCase, auditLogColdDays, auditLogWarmDays, auditLogWarmSqlCase, getAccessLogColdDays, getAccessLogWarmDays, getAuditLogColdDays, getAuditLogWarmDays, getSecretAuditLogColdDays, getSecretAuditLogWarmDays, minAccessLogWarmDays, minAuditLogWarmDays, minSecretAuditLogWarmDays, secretAuditLogColdDays, secretAuditLogWarmDays, secretAuditLogWarmSqlCase };
363
+
364
+ //# sourceMappingURL=retention-policy.js.map
@@ -0,0 +1,3 @@
1
+ export { createWorkflowBundleConfig } from './rolldown-config.js';
2
+ export type { WorkflowBundleOptions } from './rolldown-config.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,3 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ import { createWorkflowBundleConfig } from "./rolldown-config.js";
3
+ export { createWorkflowBundleConfig };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared rolldown configuration for workflow bundling.
3
+ *
4
+ * Both the compiler and agent import this factory to guarantee identical
5
+ * bundle output, which is critical for content hash verification.
6
+ */
7
+ export interface WorkflowBundleOptions {
8
+ entryPoint: string;
9
+ outfile?: string;
10
+ sourcemap?: boolean | 'inline';
11
+ alias?: Record<string, string>;
12
+ cwd?: string;
13
+ }
14
+ /**
15
+ * Create a rolldown configuration for workflow bundling.
16
+ *
17
+ * The returned config produces identical output regardless of whether
18
+ * it's called from the compiler or agent, ensuring content hash consistency.
19
+ *
20
+ * @param options - Bundle configuration
21
+ * @returns rolldown InputOptions with output config
22
+ */
23
+ export declare function createWorkflowBundleConfig(options: WorkflowBundleOptions): {
24
+ input: string;
25
+ platform: "node";
26
+ external: string[];
27
+ treeshake: boolean;
28
+ cwd: string | undefined;
29
+ resolve: {
30
+ alias: Record<string, string>;
31
+ mainFields: string[];
32
+ conditionNames: string[];
33
+ };
34
+ output: {
35
+ file: string | undefined;
36
+ format: "es";
37
+ sourcemap: boolean | "inline";
38
+ inlineDynamicImports: boolean;
39
+ };
40
+ };
41
+ //# sourceMappingURL=rolldown-config.d.ts.map
@@ -0,0 +1,40 @@
1
+ import "../chunk-gOLHoazu.js";
2
+ //#region src/bundler/rolldown-config.ts
3
+ /**
4
+ * Create a rolldown configuration for workflow bundling.
5
+ *
6
+ * The returned config produces identical output regardless of whether
7
+ * it's called from the compiler or agent, ensuring content hash consistency.
8
+ *
9
+ * @param options - Bundle configuration
10
+ * @returns rolldown InputOptions with output config
11
+ */
12
+ function createWorkflowBundleConfig(options) {
13
+ return {
14
+ input: options.entryPoint,
15
+ platform: "node",
16
+ external: [
17
+ "rolldown",
18
+ "typescript",
19
+ "zx",
20
+ "@kici-dev/sdk"
21
+ ],
22
+ treeshake: false,
23
+ cwd: options.cwd,
24
+ resolve: {
25
+ alias: options.alias ?? {},
26
+ mainFields: ["module", "main"],
27
+ conditionNames: ["import", "node"]
28
+ },
29
+ output: {
30
+ file: options.outfile,
31
+ format: "es",
32
+ sourcemap: options.sourcemap ?? false,
33
+ inlineDynamicImports: true
34
+ }
35
+ };
36
+ }
37
+ //#endregion
38
+ export { createWorkflowBundleConfig };
39
+
40
+ //# sourceMappingURL=rolldown-config.js.map
@@ -0,0 +1,4 @@
1
+ import "node:module";
2
+ import.meta.url;
3
+ //#endregion
4
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Shared environment allowlist constants for KiCI.
3
+ *
4
+ * Single source of truth for environment variable filtering used across tiers:
5
+ * - Orchestrator bare-metal backend (spawned agent processes)
6
+ * - Agent sandbox execution (customer code isolation)
7
+ *
8
+ * These constants ensure that orchestrator/agent secrets (DATABASE_URL,
9
+ * GITHUB_PRIVATE_KEY, PLATFORM_TOKEN, WEBHOOK_SECRET, etc.) are never leaked
10
+ * to child processes or customer code.
11
+ */
12
+ /**
13
+ * System environment variables that are safe to pass into spawned processes.
14
+ *
15
+ * This is an explicit allowlist -- anything NOT listed here is stripped.
16
+ * Adding new variables to the host process will NOT leak them downstream.
17
+ */
18
+ export declare const ALLOWED_SYSTEM_VARS: readonly ["PATH", "HOME", "USER", "SHELL", "LANG", "LC_ALL", "TERM", "TMPDIR", "NODE_PATH", "TZ"];
19
+ /**
20
+ * Default environment variables injected into every sandbox execution.
21
+ *
22
+ * These are set before user/secret env vars so they can be overridden.
23
+ * - FORCE_COLOR=1: Ensures color-aware libraries (chalk, etc.) emit ANSI
24
+ * codes even when stdout is a pipe (non-TTY). Without this, log output
25
+ * appears uncolored in the dashboard log viewer.
26
+ */
27
+ export declare const SANDBOX_DEFAULT_VARS: Record<string, string>;
28
+ /**
29
+ * KICI environment variables required by the agent.
30
+ *
31
+ * These are set explicitly by the scaler (not copied from orchestrator process.env)
32
+ * to ensure the agent receives only the values it needs with correct content.
33
+ */
34
+ export declare const AGENT_REQUIRED_KICI_VARS: readonly ["KICI_ORCHESTRATOR_URL", "KICI_AGENT_ID", "KICI_LABELS", "KICI_MAX_CONCURRENT_JOBS", "KICI_SCALER_MANAGED", "KICI_EXECUTION_MODE", "KICI_PORT"];
35
+ /**
36
+ * Prefix for operator-defined environment variables that should be forwarded
37
+ * from the orchestrator process to spawned agent processes.
38
+ *
39
+ * Variables with this prefix in the orchestrator's process.env are forwarded
40
+ * to agent child processes with the prefix stripped. For example:
41
+ * KICI_AGENT_ENV_HTTP_PROXY=http://proxy:3128
42
+ * -> HTTP_PROXY=http://proxy:3128 in the agent process
43
+ */
44
+ export declare const KICI_AGENT_ENV_PREFIX: "KICI_AGENT_ENV_";
45
+ //# sourceMappingURL=environment-allowlist.d.ts.map