@fourier-labs/harbour-contracts 0.3.1 → 0.5.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 (92) hide show
  1. package/README.md +1 -1
  2. package/dist/gen-ts/ai-callsite-inventory.d.ts +49 -0
  3. package/dist/gen-ts/ai-gateway-key-lookup.d.ts +20 -0
  4. package/dist/gen-ts/ai-gateway-key-token.d.ts +4 -0
  5. package/dist/gen-ts/ai-gateway-key-token.js +6 -0
  6. package/dist/gen-ts/ai-governance-decision.d.ts +74 -0
  7. package/dist/gen-ts/ai-policy-snapshot.d.ts +429 -0
  8. package/dist/gen-ts/ai-runtime-contract.d.ts +27 -0
  9. package/dist/gen-ts/ai-trace-event.d.ts +68 -0
  10. package/dist/gen-ts/ai-transform-event.d.ts +66 -0
  11. package/dist/gen-ts/ai-transform-result.d.ts +32 -0
  12. package/dist/gen-ts/ai-verification-evidence.d.ts +49 -0
  13. package/dist/gen-ts/data-dependency.d.ts +42 -0
  14. package/dist/gen-ts/data-grant.d.ts +58 -0
  15. package/dist/gen-ts/data-grant.js +12 -0
  16. package/dist/gen-ts/data-source.d.ts +74 -0
  17. package/dist/{deploy-request.d.ts → gen-ts/deploy-request.d.ts} +30 -0
  18. package/dist/gen-ts/deploy-response.js +3 -0
  19. package/dist/gen-ts/deployment-environment.js +3 -0
  20. package/dist/gen-ts/deployment-source.js +3 -0
  21. package/dist/gen-ts/deployment-status-failure.js +3 -0
  22. package/dist/gen-ts/deployment-status-request.js +3 -0
  23. package/dist/{deployment-status-response.d.ts → gen-ts/deployment-status-response.d.ts} +2 -2
  24. package/dist/gen-ts/deployment-status-response.js +3 -0
  25. package/dist/gen-ts/env-bindings.js +3 -0
  26. package/dist/{error-category-registry.d.ts → gen-ts/error-category-registry.d.ts} +7 -0
  27. package/dist/{error-category-registry.js → gen-ts/error-category-registry.js} +14 -0
  28. package/dist/gen-ts/error-category.js +3 -0
  29. package/dist/gen-ts/error-envelope.js +3 -0
  30. package/dist/{index.d.ts → gen-ts/index.d.ts} +16 -0
  31. package/dist/{index.js → gen-ts/index.js} +16 -0
  32. package/dist/gen-ts/kvs-routing-entry.js +3 -0
  33. package/dist/gen-ts/promotion-request.d.ts +17 -0
  34. package/dist/gen-ts/promotion-request.js +3 -0
  35. package/dist/gen-ts/promotion-response.d.ts +17 -0
  36. package/dist/gen-ts/promotion-response.js +3 -0
  37. package/dist/gen-ts/secret-reference.d.ts +36 -0
  38. package/dist/gen-ts/secret-reference.js +3 -0
  39. package/dist/{version-state-machine.d.ts → gen-ts/version-state-machine.d.ts} +7 -2
  40. package/dist/gen-ts/version-state-machine.js +45 -0
  41. package/dist/gen-ts/version-state.js +3 -0
  42. package/dist/resolver/index.d.ts +256 -0
  43. package/dist/resolver/index.js +679 -0
  44. package/package.json +14 -4
  45. package/schema/ai-callsite-inventory.schema.json +138 -0
  46. package/schema/ai-gateway-key-lookup.schema.json +53 -0
  47. package/schema/ai-governance-decision.schema.json +105 -0
  48. package/schema/ai-policy-snapshot.schema.json +340 -0
  49. package/schema/ai-runtime-contract.schema.json +85 -0
  50. package/schema/ai-trace-event.schema.json +178 -0
  51. package/schema/ai-transform-event.schema.json +72 -0
  52. package/schema/ai-transform-result.schema.json +46 -0
  53. package/schema/ai-verification-evidence.schema.json +57 -0
  54. package/schema/data-dependency.schema.json +89 -0
  55. package/schema/data-grant.schema.json +107 -0
  56. package/schema/data-source.schema.json +151 -0
  57. package/schema/deploy-request.schema.json +60 -0
  58. package/schema/deploy-response.schema.json +1 -1
  59. package/schema/deployment-status-request.schema.json +1 -1
  60. package/schema/deployment-status-response.schema.json +2 -2
  61. package/schema/error-category.enum.json +7 -0
  62. package/schema/promotion-request.schema.json +26 -0
  63. package/schema/promotion-response.schema.json +50 -0
  64. package/schema/secret-reference.schema.json +70 -0
  65. package/schema/version-state.schema.json +25 -24
  66. package/dist/version-state-machine.js +0 -35
  67. /package/dist/{api-error-response.js → gen-ts/ai-callsite-inventory.js} +0 -0
  68. /package/dist/{artifact-contract.js → gen-ts/ai-gateway-key-lookup.js} +0 -0
  69. /package/dist/{deploy-request.js → gen-ts/ai-governance-decision.js} +0 -0
  70. /package/dist/{deploy-response.js → gen-ts/ai-policy-snapshot.js} +0 -0
  71. /package/dist/{deployment-environment.js → gen-ts/ai-runtime-contract.js} +0 -0
  72. /package/dist/{deployment-source.js → gen-ts/ai-trace-event.js} +0 -0
  73. /package/dist/{deployment-status-failure.js → gen-ts/ai-transform-event.js} +0 -0
  74. /package/dist/{deployment-status-request.js → gen-ts/ai-transform-result.js} +0 -0
  75. /package/dist/{deployment-status-response.js → gen-ts/ai-verification-evidence.js} +0 -0
  76. /package/dist/{api-error-response.d.ts → gen-ts/api-error-response.d.ts} +0 -0
  77. /package/dist/{env-bindings.js → gen-ts/api-error-response.js} +0 -0
  78. /package/dist/{artifact-contract.d.ts → gen-ts/artifact-contract.d.ts} +0 -0
  79. /package/dist/{error-category.js → gen-ts/artifact-contract.js} +0 -0
  80. /package/dist/{error-envelope.js → gen-ts/data-dependency.js} +0 -0
  81. /package/dist/{kvs-routing-entry.js → gen-ts/data-source.js} +0 -0
  82. /package/dist/{version-state.js → gen-ts/deploy-request.js} +0 -0
  83. /package/dist/{deploy-response.d.ts → gen-ts/deploy-response.d.ts} +0 -0
  84. /package/dist/{deployment-environment.d.ts → gen-ts/deployment-environment.d.ts} +0 -0
  85. /package/dist/{deployment-source.d.ts → gen-ts/deployment-source.d.ts} +0 -0
  86. /package/dist/{deployment-status-failure.d.ts → gen-ts/deployment-status-failure.d.ts} +0 -0
  87. /package/dist/{deployment-status-request.d.ts → gen-ts/deployment-status-request.d.ts} +0 -0
  88. /package/dist/{env-bindings.d.ts → gen-ts/env-bindings.d.ts} +0 -0
  89. /package/dist/{error-category.d.ts → gen-ts/error-category.d.ts} +0 -0
  90. /package/dist/{error-envelope.d.ts → gen-ts/error-envelope.d.ts} +0 -0
  91. /package/dist/{kvs-routing-entry.d.ts → gen-ts/kvs-routing-entry.d.ts} +0 -0
  92. /package/dist/{version-state.d.ts → gen-ts/version-state.d.ts} +0 -0
@@ -0,0 +1,72 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.harbour.dev/ai-transform-event.schema.json",
4
+ "title": "AiTransformEvent",
5
+ "description": "Checksum-bound deterministic AI interception task input. Entries are the complete ordered PLAN interception plan so the task can verify the governance plan digest before applying its deterministic subset; source and patches are referenced, never embedded.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema", "tenantId", "appId", "environment", "versionId", "sourceRevision", "workspace", "inventoryDigest", "policyDigest", "runtimeContractDigest", "interceptionPlanDigest", "entries"],
9
+ "properties": {
10
+ "schema": { "type": "string", "const": "harbour.ai-transform-event/1.0" },
11
+ "tenantId": { "$ref": "#/definitions/AiTransformIdentifier" },
12
+ "appId": { "$ref": "#/definitions/AiTransformIdentifier" },
13
+ "environment": { "$ref": "#/definitions/AiTransformIdentifier" },
14
+ "versionId": { "type": "string", "minLength": 7, "maxLength": 320, "pattern": "^[^#]+#[^#]+#[^#]+#[0-9]{6,}$" },
15
+ "sourceRevision": { "type": "string", "minLength": 7, "maxLength": 128 },
16
+ "workspace": { "$ref": "#/definitions/AiTransformWorkspace" },
17
+ "inventoryDigest": { "$ref": "#/definitions/AiTransformDigest" },
18
+ "policyDigest": { "$ref": "#/definitions/AiTransformDigest" },
19
+ "runtimeContractDigest": { "$ref": "#/definitions/AiTransformDigest" },
20
+ "interceptionPlanDigest": { "$ref": "#/definitions/AiTransformDigest" },
21
+ "entries": {
22
+ "type": "array",
23
+ "minItems": 1,
24
+ "maxItems": 1000,
25
+ "items": { "$ref": "#/definitions/AiTransformPlanEntry" }
26
+ }
27
+ },
28
+ "definitions": {
29
+ "AiTransformIdentifier": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^[A-Za-z0-9][A-Za-z0-9_.@/-]*$" },
30
+ "AiTransformDigest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
31
+ "AiTransformWorkspace": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": ["bucket", "key", "sha256", "size"],
35
+ "properties": {
36
+ "bucket": { "type": "string", "minLength": 3, "maxLength": 63 },
37
+ "key": { "type": "string", "minLength": 1, "maxLength": 1024 },
38
+ "sha256": { "$ref": "#/definitions/AiTransformDigest" },
39
+ "size": { "type": "integer", "minimum": 1, "maximum": 536870912 }
40
+ }
41
+ },
42
+ "AiTransformPlanEntry": {
43
+ "type": "object",
44
+ "additionalProperties": false,
45
+ "required": ["callSiteFingerprint", "sourcePath", "expectedSourceFileSha256", "strategy", "allowedSyntaxKinds"],
46
+ "properties": {
47
+ "callSiteFingerprint": { "$ref": "#/definitions/AiTransformDigest" },
48
+ "sourcePath": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))[^\\u0000]+$" },
49
+ "expectedSourceFileSha256": { "$ref": "#/definitions/AiTransformDigest" },
50
+ "strategy": { "type": "string", "enum": ["deployment_injection", "deterministic_adapter"] },
51
+ "configurationMappingId": { "$ref": "#/definitions/AiTransformIdentifier" },
52
+ "configurationMappingVersion": { "type": "string", "minLength": 1, "maxLength": 128 },
53
+ "transformId": { "$ref": "#/definitions/AiTransformIdentifier" },
54
+ "transformVersion": { "type": "string", "minLength": 1, "maxLength": 128 },
55
+ "allowedSyntaxKinds": { "type": "array", "minItems": 1, "maxItems": 32, "uniqueItems": true, "items": { "$ref": "#/definitions/AiTransformIdentifier" } },
56
+ "runtimeShimName": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^@?[A-Za-z0-9][A-Za-z0-9_.@/-]*$" },
57
+ "runtimeShimVersion": { "type": "string", "minLength": 1, "maxLength": 128 },
58
+ "runtimeShimDigest": { "$ref": "#/definitions/AiTransformDigest" }
59
+ },
60
+ "allOf": [
61
+ {
62
+ "if": { "properties": { "strategy": { "const": "deployment_injection" } }, "required": ["strategy"] },
63
+ "then": { "required": ["configurationMappingId", "configurationMappingVersion"] }
64
+ },
65
+ {
66
+ "if": { "properties": { "strategy": { "const": "deterministic_adapter" } }, "required": ["strategy"] },
67
+ "then": { "required": ["transformId", "transformVersion", "runtimeShimName", "runtimeShimVersion", "runtimeShimDigest"] }
68
+ }
69
+ ]
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.harbour.dev/ai-transform-result.schema.json",
4
+ "title": "AiTransformResult",
5
+ "description": "Bounded deterministic interception result; contains descriptors and digest evidence only.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema", "workspace", "interceptionPlanDigest", "transformerVersion", "applied"],
9
+ "properties": {
10
+ "schema": { "type": "string", "const": "harbour.ai-transform-result/1.0" },
11
+ "workspace": { "$ref": "#/definitions/AiTransformResultWorkspace" },
12
+ "interceptionPlanDigest": { "$ref": "#/definitions/AiTransformResultDigest" },
13
+ "transformerVersion": { "type": "string", "minLength": 1, "maxLength": 128 },
14
+ "applied": { "type": "array", "minItems": 1, "maxItems": 1000, "items": { "$ref": "#/definitions/AiTransformApplied" } }
15
+ },
16
+ "definitions": {
17
+ "AiTransformResultIdentifier": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^[A-Za-z0-9][A-Za-z0-9_.@/-]*$" },
18
+ "AiTransformResultDigest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
19
+ "AiTransformResultWorkspace": {
20
+ "type": "object",
21
+ "additionalProperties": false,
22
+ "required": ["bucket", "key", "sha256", "size"],
23
+ "properties": {
24
+ "bucket": { "type": "string", "minLength": 3, "maxLength": 63 },
25
+ "key": { "type": "string", "minLength": 1, "maxLength": 1024 },
26
+ "sha256": { "$ref": "#/definitions/AiTransformResultDigest" },
27
+ "size": { "type": "integer", "minimum": 1, "maximum": 536870912 }
28
+ }
29
+ },
30
+ "AiTransformApplied": {
31
+ "type": "object",
32
+ "additionalProperties": false,
33
+ "required": ["callSiteFingerprint", "transformId", "transformVersion", "sourcePath", "beforeSha256", "afterSha256", "governedBoundaryFingerprint", "runtimeShimDigest"],
34
+ "properties": {
35
+ "callSiteFingerprint": { "$ref": "#/definitions/AiTransformResultDigest" },
36
+ "transformId": { "$ref": "#/definitions/AiTransformResultIdentifier" },
37
+ "transformVersion": { "type": "string", "minLength": 1, "maxLength": 128 },
38
+ "sourcePath": { "type": "string", "minLength": 1, "maxLength": 512, "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))[^\\u0000]+$" },
39
+ "beforeSha256": { "$ref": "#/definitions/AiTransformResultDigest" },
40
+ "afterSha256": { "$ref": "#/definitions/AiTransformResultDigest" },
41
+ "governedBoundaryFingerprint": { "$ref": "#/definitions/AiTransformResultDigest" },
42
+ "runtimeShimDigest": { "$ref": "#/definitions/AiTransformResultDigest" }
43
+ }
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.harbour.dev/ai-verification-evidence.schema.json",
4
+ "title": "AiVerificationEvidence",
5
+ "description": "Bounded, value-free evidence submitted by deployment verification for one governed version.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema", "tenantId", "appId", "environment", "versionId", "sourceRevision", "inventoryDigest", "interceptionPlanDigest", "runtimeContractDigest", "policyDigest", "finalWorkspaceDigest", "verifiedCallsiteFingerprints", "appliedTransforms", "endpointChecks", "providerCredentialsAbsent", "smokeTraceId", "evidenceDigest", "verifiedAt"],
9
+ "properties": {
10
+ "schema": { "type": "string", "const": "harbour.ai-verification-evidence/1.0" },
11
+ "tenantId": { "$ref": "#/definitions/AiVerificationIdentifier" },
12
+ "appId": { "$ref": "#/definitions/AiVerificationIdentifier" },
13
+ "environment": { "$ref": "#/definitions/AiVerificationIdentifier" },
14
+ "versionId": { "type": "string", "minLength": 7, "maxLength": 320, "pattern": "^[^#]+#[^#]+#[^#]+#[0-9]{6,}$" },
15
+ "sourceRevision": { "type": "string", "minLength": 7, "maxLength": 128 },
16
+ "inventoryDigest": { "$ref": "#/definitions/AiVerificationDigest" },
17
+ "interceptionPlanDigest": { "$ref": "#/definitions/AiVerificationDigest" },
18
+ "runtimeContractDigest": { "$ref": "#/definitions/AiVerificationDigest" },
19
+ "policyDigest": { "$ref": "#/definitions/AiVerificationDigest" },
20
+ "finalWorkspaceDigest": { "$ref": "#/definitions/AiVerificationDigest" },
21
+ "verifiedCallsiteFingerprints": { "type": "array", "maxItems": 1000, "uniqueItems": true, "items": { "$ref": "#/definitions/AiVerificationDigest" } },
22
+ "appliedTransforms": { "type": "array", "maxItems": 1000, "items": { "$ref": "#/definitions/AiVerificationTransform" } },
23
+ "endpointChecks": { "type": "array", "minItems": 1, "maxItems": 32, "items": { "$ref": "#/definitions/AiVerificationEndpointCheck" } },
24
+ "providerCredentialsAbsent": { "type": "boolean", "const": true },
25
+ "smokeTraceId": { "type": "string", "pattern": "^trc_[A-Za-z0-9_-]+$", "maxLength": 160 },
26
+ "evidenceDigest": { "$ref": "#/definitions/AiVerificationDigest" },
27
+ "verifiedAt": { "type": "string", "format": "date-time" }
28
+ },
29
+ "definitions": {
30
+ "AiVerificationIdentifier": { "type": "string", "minLength": 1, "maxLength": 160, "pattern": "^[A-Za-z0-9][A-Za-z0-9_.@/-]*$" },
31
+ "AiVerificationDigest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
32
+ "AiVerificationTransform": {
33
+ "type": "object",
34
+ "additionalProperties": false,
35
+ "required": ["callSiteFingerprint", "governedBoundaryFingerprint", "transformId", "transformVersion", "beforeSha256", "afterSha256", "runtimeShimDigest"],
36
+ "properties": {
37
+ "callSiteFingerprint": { "$ref": "#/definitions/AiVerificationDigest" },
38
+ "governedBoundaryFingerprint": { "$ref": "#/definitions/AiVerificationDigest" },
39
+ "transformId": { "$ref": "#/definitions/AiVerificationIdentifier" },
40
+ "transformVersion": { "type": "string", "minLength": 1, "maxLength": 128 },
41
+ "beforeSha256": { "$ref": "#/definitions/AiVerificationDigest" },
42
+ "afterSha256": { "$ref": "#/definitions/AiVerificationDigest" },
43
+ "runtimeShimDigest": { "$ref": "#/definitions/AiVerificationDigest" }
44
+ }
45
+ },
46
+ "AiVerificationEndpointCheck": {
47
+ "type": "object",
48
+ "additionalProperties": false,
49
+ "required": ["name", "passed", "configurationMappingVersion"],
50
+ "properties": {
51
+ "name": { "$ref": "#/definitions/AiVerificationIdentifier" },
52
+ "passed": { "type": "boolean", "const": true },
53
+ "configurationMappingVersion": { "type": "string", "minLength": 1, "maxLength": 128 }
54
+ }
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,89 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.harbour.dev/data-dependency.schema.json",
4
+ "title": "DataDependency",
5
+ "description": "A single external data dependency of an app, either declared by the builder or detected during analysis. Classification records how the dependency resolved against the tenant's registered data-source inventory; matchedSourceId is present only when classification is matched.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["kind", "identifiers", "classification", "origin"],
9
+ "properties": {
10
+ "kind": {
11
+ "$ref": "#/definitions/DataDependencyKind"
12
+ },
13
+ "identifiers": {
14
+ "$ref": "#/definitions/DataDependencyIdentifiers"
15
+ },
16
+ "classification": {
17
+ "$ref": "#/definitions/DataDependencyClassification"
18
+ },
19
+ "matchedSourceId": {
20
+ "type": "string",
21
+ "minLength": 1,
22
+ "maxLength": 255,
23
+ "description": "sourceId of the registered data source this dependency matched; present only when classification is matched."
24
+ },
25
+ "origin": {
26
+ "$ref": "#/definitions/DataDependencyOrigin"
27
+ }
28
+ },
29
+ "definitions": {
30
+ "DataDependencyKind": {
31
+ "type": "string",
32
+ "enum": ["database", "api", "app_owned_external"],
33
+ "description": "database = a SQL/warehouse connection; api = an HTTP(S) service; app_owned_external = infrastructure the app owns outside Harbour."
34
+ },
35
+ "DataDependencyIdentifiers": {
36
+ "type": "object",
37
+ "additionalProperties": false,
38
+ "required": ["hosts", "envNames"],
39
+ "properties": {
40
+ "hosts": {
41
+ "type": "array",
42
+ "items": {
43
+ "type": "string",
44
+ "minLength": 1
45
+ },
46
+ "description": "Hostnames the dependency was observed or declared against."
47
+ },
48
+ "driver": {
49
+ "type": "string",
50
+ "minLength": 1,
51
+ "maxLength": 255,
52
+ "description": "Client driver/library that surfaced the dependency (e.g. pg, snowflake-sdk)."
53
+ },
54
+ "envNames": {
55
+ "type": "array",
56
+ "items": {
57
+ "type": "string",
58
+ "minLength": 1
59
+ },
60
+ "description": "Environment-variable names the app reads to configure this dependency."
61
+ }
62
+ },
63
+ "description": "Evidence identifying the dependency; used to match it against the registered source inventory."
64
+ },
65
+ "DataDependencyClassification": {
66
+ "type": "string",
67
+ "enum": ["matched", "out_of_scope", "unknown", "inventory", "app_owned_external"],
68
+ "description": "matched = resolved to a registered source; out_of_scope = resolved but not requestable; unknown = unresolvable; inventory = registered but unused; app_owned_external = app-owned, outside Harbour's remit."
69
+ },
70
+ "DataDependencyOrigin": {
71
+ "type": "string",
72
+ "enum": ["declared", "detected"],
73
+ "description": "declared = stated by the builder; detected = found by analysis."
74
+ }
75
+ },
76
+ "examples": [
77
+ {
78
+ "kind": "database",
79
+ "identifiers": {
80
+ "hosts": ["analytics.internal.example.com"],
81
+ "driver": "pg",
82
+ "envNames": ["DATABASE_URL"]
83
+ },
84
+ "classification": "matched",
85
+ "matchedSourceId": "analytics-warehouse",
86
+ "origin": "detected"
87
+ }
88
+ ]
89
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.harbour.dev/data-grant.schema.json",
4
+ "title": "DataGrant",
5
+ "description": "An app's approved (or requested) read scope against a registered data source. MVP is deliberately narrow: mode is read-only and identityModel is service (one minted principal per grant, no per-end-user identity passthrough). Grant status is a tiny state machine — legal edges live in x-transitions and codegen turns them into shared CanTransitionDataGrantStatus / IsTerminalDataGrantStatus helpers so control-plane and consumers agree on legality.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["appId", "sourceId", "scope", "mode", "identityModel", "status"],
9
+ "properties": {
10
+ "appId": {
11
+ "type": "string",
12
+ "minLength": 1,
13
+ "maxLength": 255,
14
+ "description": "App the grant belongs to."
15
+ },
16
+ "sourceId": {
17
+ "type": "string",
18
+ "minLength": 1,
19
+ "maxLength": 255,
20
+ "description": "Registered data source the grant targets (data-source.schema.json)."
21
+ },
22
+ "scope": {
23
+ "type": "array",
24
+ "items": {
25
+ "type": "string",
26
+ "minLength": 1
27
+ },
28
+ "minItems": 1,
29
+ "description": "Requested/granted selectors; every selector must fall inside the source's allowedScope."
30
+ },
31
+ "mode": {
32
+ "$ref": "#/definitions/DataGrantMode"
33
+ },
34
+ "identityModel": {
35
+ "$ref": "#/definitions/DataGrantIdentityModel"
36
+ },
37
+ "status": {
38
+ "$ref": "#/definitions/DataGrantStatus"
39
+ },
40
+ "credentialRef": {
41
+ "type": "string",
42
+ "pattern": "^secretref://[A-Za-z0-9][A-Za-z0-9/_.:-]*$",
43
+ "description": "secretref URI of the minted per-grant credential; present once GRANTED."
44
+ },
45
+ "mintedPrincipal": {
46
+ "type": "string",
47
+ "minLength": 1,
48
+ "maxLength": 255,
49
+ "description": "Name of the scoped principal minted on the source for this grant; present once GRANTED."
50
+ },
51
+ "requestedByOperationId": {
52
+ "type": "string",
53
+ "minLength": 1,
54
+ "maxLength": 255,
55
+ "description": "Operation (e.g. deployment analysis) that raised the request, for audit correlation."
56
+ },
57
+ "approvedBy": {
58
+ "type": "string",
59
+ "minLength": 1,
60
+ "maxLength": 255,
61
+ "description": "Admin identity that resolved the request; present once GRANTED or DENIED."
62
+ },
63
+ "approvedAt": {
64
+ "type": "string",
65
+ "format": "date-time",
66
+ "description": "RFC 3339 instant the request was resolved; present once GRANTED or DENIED."
67
+ }
68
+ },
69
+ "definitions": {
70
+ "DataGrantMode": {
71
+ "type": "string",
72
+ "enum": ["read"],
73
+ "description": "Access mode. MVP is read-only; write is a deliberate future schema change."
74
+ },
75
+ "DataGrantIdentityModel": {
76
+ "type": "string",
77
+ "enum": ["service"],
78
+ "description": "MVP: one minted service principal per grant. Per-end-user passthrough is a future schema change."
79
+ },
80
+ "DataGrantStatus": {
81
+ "type": "string",
82
+ "enum": ["REQUESTED", "GRANTED", "DENIED"],
83
+ "description": "Grant lifecycle state. Legal edges live in x-transitions; GRANTED and DENIED are terminal."
84
+ }
85
+ },
86
+ "x-status-definition": "DataGrantStatus",
87
+ "x-terminal": ["GRANTED", "DENIED"],
88
+ "x-transitions": [
89
+ { "from": "REQUESTED", "to": "GRANTED", "trigger": "admin approves: scope within allowedScope, principal minted, credentialRef set" },
90
+ { "from": "REQUESTED", "to": "DENIED", "trigger": "admin declines the request" }
91
+ ],
92
+ "examples": [
93
+ {
94
+ "appId": "reports",
95
+ "sourceId": "analytics-warehouse",
96
+ "scope": ["public.orders"],
97
+ "mode": "read",
98
+ "identityModel": "service",
99
+ "status": "GRANTED",
100
+ "credentialRef": "secretref://tenants/fourier/grants/reports/analytics-warehouse",
101
+ "mintedPrincipal": "harbour_grant_reports_analytics",
102
+ "requestedByOperationId": "fourier#reports#preview#1000042",
103
+ "approvedBy": "admin@fourier.example",
104
+ "approvedAt": "2026-08-05T12:00:00Z"
105
+ }
106
+ ]
107
+ }
@@ -0,0 +1,151 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://schemas.harbour.dev/data-source.schema.json",
4
+ "title": "DataSource",
5
+ "description": "An admin-registered external data source (Data-Access MVP). The credential the platform holds for the source never crosses this boundary — credentialRef is a secretref URI resolved internally. allowedScope is the admin-declared selector allowlist grants are checked against; observedScope is what discovery actually saw and is informational only.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "tenantId",
10
+ "sourceId",
11
+ "connector",
12
+ "displayName",
13
+ "endpoint",
14
+ "credentialRef",
15
+ "provisioningMode",
16
+ "allowedScope",
17
+ "requestableByBuilders",
18
+ "status"
19
+ ],
20
+ "properties": {
21
+ "tenantId": {
22
+ "type": "string",
23
+ "minLength": 1,
24
+ "maxLength": 255,
25
+ "description": "Owning tenant (org) identifier."
26
+ },
27
+ "sourceId": {
28
+ "type": "string",
29
+ "minLength": 1,
30
+ "maxLength": 255,
31
+ "description": "Tenant-unique data-source identifier."
32
+ },
33
+ "connector": {
34
+ "$ref": "#/definitions/DataSourceConnector"
35
+ },
36
+ "displayName": {
37
+ "type": "string",
38
+ "minLength": 1,
39
+ "maxLength": 255,
40
+ "description": "Human-readable name shown to admins and builders."
41
+ },
42
+ "endpoint": {
43
+ "$ref": "#/definitions/DataSourceEndpoint"
44
+ },
45
+ "credentialRef": {
46
+ "type": "string",
47
+ "pattern": "^secretref://[A-Za-z0-9][A-Za-z0-9/_.:-]*$",
48
+ "description": "secretref URI naming the platform-held credential for this source. The referenced value never crosses this boundary."
49
+ },
50
+ "provisioningMode": {
51
+ "$ref": "#/definitions/DataSourceProvisioningMode"
52
+ },
53
+ "allowedScope": {
54
+ "type": "array",
55
+ "items": {
56
+ "type": "string",
57
+ "minLength": 1
58
+ },
59
+ "description": "Admin-declared selector allowlist (e.g. schema.table patterns) that grant scopes are validated against."
60
+ },
61
+ "observedScope": {
62
+ "type": "array",
63
+ "items": {
64
+ "type": "string",
65
+ "minLength": 1
66
+ },
67
+ "description": "Selectors discovery actually observed on the source. Informational; never widens allowedScope."
68
+ },
69
+ "requestableByBuilders": {
70
+ "type": "boolean",
71
+ "description": "Whether builders may request grants against this source."
72
+ },
73
+ "status": {
74
+ "$ref": "#/definitions/DataSourceStatus"
75
+ }
76
+ },
77
+ "definitions": {
78
+ "DataSourceConnector": {
79
+ "type": "string",
80
+ "enum": ["postgres", "redshift", "bigquery", "databricks"],
81
+ "description": "Closed connector set for the Data-Access MVP."
82
+ },
83
+ "DataSourceEndpoint": {
84
+ "type": "object",
85
+ "additionalProperties": false,
86
+ "required": ["host"],
87
+ "properties": {
88
+ "host": {
89
+ "type": "string",
90
+ "minLength": 1,
91
+ "maxLength": 255,
92
+ "description": "Network host (or warehouse endpoint) of the source."
93
+ },
94
+ "port": {
95
+ "type": "integer",
96
+ "minimum": 1,
97
+ "maximum": 65535,
98
+ "description": "TCP port; absent where the connector implies it."
99
+ },
100
+ "database": {
101
+ "type": "string",
102
+ "minLength": 1,
103
+ "maxLength": 255,
104
+ "description": "Database name (postgres/redshift-style connectors)."
105
+ },
106
+ "project": {
107
+ "type": "string",
108
+ "minLength": 1,
109
+ "maxLength": 255,
110
+ "description": "Project identifier (bigquery-style connectors)."
111
+ },
112
+ "workspace": {
113
+ "type": "string",
114
+ "minLength": 1,
115
+ "maxLength": 255,
116
+ "description": "Workspace identifier (databricks-style connectors)."
117
+ }
118
+ },
119
+ "description": "Connector endpoint coordinates. host is always present; database vs project/workspace depends on the connector family."
120
+ },
121
+ "DataSourceProvisioningMode": {
122
+ "type": "string",
123
+ "enum": ["byo", "harbour_managed"],
124
+ "description": "byo = admin brought existing infrastructure; harbour_managed = Harbour provisioned it."
125
+ },
126
+ "DataSourceStatus": {
127
+ "type": "string",
128
+ "enum": ["ACTIVE", "DISABLED"],
129
+ "description": "DISABLED sources reject new grants and suspend existing access."
130
+ }
131
+ },
132
+ "examples": [
133
+ {
134
+ "tenantId": "fourier",
135
+ "sourceId": "analytics-warehouse",
136
+ "connector": "postgres",
137
+ "displayName": "Analytics Warehouse",
138
+ "endpoint": {
139
+ "host": "analytics.internal.example.com",
140
+ "port": 5432,
141
+ "database": "analytics"
142
+ },
143
+ "credentialRef": "secretref://tenants/fourier/sources/analytics-warehouse/admin",
144
+ "provisioningMode": "byo",
145
+ "allowedScope": ["public.orders", "public.customers"],
146
+ "observedScope": ["public.orders", "public.customers", "public.internal_audit"],
147
+ "requestableByBuilders": true,
148
+ "status": "ACTIVE"
149
+ }
150
+ ]
151
+ }
@@ -30,9 +30,54 @@
30
30
  "type": "string",
31
31
  "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{7,127}$",
32
32
  "description": "Optional legacy request-correlation value returned as requestId. It does not make repeated HTTP POSTs idempotent; versionId is the deployment identity and SQS deduplication key."
33
+ },
34
+ "environmentBindings": {
35
+ "$ref": "#/definitions/DeployRequestEnvironmentBindings"
33
36
  }
34
37
  },
35
38
  "definitions": {
39
+ "DeployRequestEnvironmentBindings": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "required": ["bindings"],
43
+ "properties": {
44
+ "bindings": {
45
+ "type": "array",
46
+ "items": {
47
+ "$ref": "#/definitions/DeployRequestEnvironmentBinding"
48
+ },
49
+ "description": "Environment-variable bindings for this deployment."
50
+ }
51
+ },
52
+ "description": "Optional runtime environment configuration (Secret-Manager MVP). Named environmentBindings, not environment — the existing required `environment` property is the deployment-target token and predates this object. Additive: requests without it remain valid."
53
+ },
54
+ "DeployRequestEnvironmentBinding": {
55
+ "type": "object",
56
+ "additionalProperties": false,
57
+ "required": ["name"],
58
+ "properties": {
59
+ "name": {
60
+ "type": "string",
61
+ "minLength": 1,
62
+ "maxLength": 255,
63
+ "description": "Environment-variable name the app reads."
64
+ },
65
+ "secretRef": {
66
+ "type": "string",
67
+ "pattern": "^secretref://[A-Za-z0-9][A-Za-z0-9/_.:-]*$",
68
+ "description": "secretref URI resolved at runtime; the value never appears in the request."
69
+ },
70
+ "value": {
71
+ "type": "string",
72
+ "description": "Plain (non-secret) literal value."
73
+ }
74
+ },
75
+ "oneOf": [
76
+ { "required": ["secretRef"] },
77
+ { "required": ["value"] }
78
+ ],
79
+ "description": "One environment-variable binding: exactly one of secretRef (secret, resolved at runtime) or value (plain literal)."
80
+ },
36
81
  "DeployRequestSource": {
37
82
  "type": "object",
38
83
  "additionalProperties": false,
@@ -63,6 +108,21 @@
63
108
  "branch": "preview-deployment",
64
109
  "commit": "abc1234567890abcdef1234567890abcdef12345",
65
110
  "idempotencyKey": "deploy-attempt-123"
111
+ },
112
+ {
113
+ "source": {
114
+ "provider": "github",
115
+ "repositoryUrl": "https://github.com/Fourier-Labs-AI/focus-list"
116
+ },
117
+ "environment": "preview",
118
+ "branch": "preview-deployment",
119
+ "commit": "abc1234567890abcdef1234567890abcdef12345",
120
+ "environmentBindings": {
121
+ "bindings": [
122
+ { "name": "STRIPE_API_KEY", "secretRef": "secretref://tenants/fourier/apps/reports/STRIPE_API_KEY" },
123
+ { "name": "LOG_LEVEL", "value": "debug" }
124
+ ]
125
+ }
66
126
  }
67
127
  ]
68
128
  }
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "versionId": {
17
17
  "type": "string",
18
- "pattern": "^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?#[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?#preview#[0-9]{6}$",
18
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?#[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?#preview#[0-9]{6,}$",
19
19
  "description": "Immutable identity of the admitted preview version."
20
20
  },
21
21
  "tenant": {
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "versionId": {
21
21
  "type": "string",
22
- "pattern": "^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?#[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?#preview#[0-9]{6}$"
22
+ "pattern": "^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?#[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?#(?:preview|prod)#[0-9]{6,}$"
23
23
  }
24
24
  }
25
25
  }
@@ -21,11 +21,11 @@
21
21
  },
22
22
  "environment": {
23
23
  "type": "string",
24
- "enum": ["preview"]
24
+ "enum": ["preview", "prod"]
25
25
  },
26
26
  "status": {
27
27
  "type": "string",
28
- "enum": ["QUEUED", "ANALYZING", "TRANSFORMING", "VALIDATING", "BUILDING", "VERIFYING", "GATING", "LIVE", "FAILED", "STALE"]
28
+ "enum": ["QUEUED", "ANALYZING", "TRANSFORMING", "VALIDATING", "BUILDING", "VERIFYING", "GATING", "LIVE", "AWAITING-PROMOTION", "PROMOTING", "FAILED", "STALE"]
29
29
  },
30
30
  "message": {
31
31
  "type": "string",