@opensoftware/contracts 1.5.0 → 1.6.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.
package/README.md CHANGED
@@ -43,6 +43,7 @@ Each format has one schema, generated from `typespec/`, and fixtures that CONTRA
43
43
  | evidence bundle | `evidence-bundle/evidence-bundle.schema.json` | `EvidenceManifest` | `evidence.json` at the bundle root. |
44
44
  | score | `score/score.schema.json` | `Score` | Subset of Langfuse's create-score request; factory fields in `metadata`. |
45
45
  | gate record | `gate-record/gate-record.schema.json` | `GateRecord` | gatekeeper's signed approval record (ADR 0047). |
46
+ | sandbox spec | `sandbox-spec/sandbox-spec.schema.json` | `SandboxSpec` | The input of a sandbox adapter's `create` (ADR 0054). Closed objects: an unknown field is an error. |
46
47
  | events | `events/<event>/<event>.schema.json`, `events/asyncapi.yaml` | `WorkReceived` … `PrClosed` | CloudEvents 1.0, structured JSON. |
47
48
 
48
49
  ## HTTP APIs
package/dist/formats.js CHANGED
@@ -7,6 +7,7 @@ export const FORMATS = [
7
7
  format("evidence-bundle", "EvidenceManifest"),
8
8
  format("score", "Score"),
9
9
  format("gate-record", "GateRecord"),
10
+ format("sandbox-spec", "SandboxSpec"),
10
11
  format("events/work-received", "WorkReceived"),
11
12
  format("events/run-completed", "RunCompleted"),
12
13
  format("events/gate-requested", "GateRequested"),
@@ -1 +1 @@
1
- {"version":3,"file":"formats.js","sourceRoot":"","sources":["../src/formats.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAW3G,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAY,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAEjH,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,MAAM,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC;IAC/B,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC;IACjC,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;IAC7C,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC;IACnC,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;IAC9C,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;IAC9C,MAAM,CAAC,uBAAuB,EAAE,eAAe,CAAC;IAChD,MAAM,CAAC,qBAAqB,EAAE,aAAa,CAAC;IAC5C,MAAM,CAAC,uBAAuB,EAAE,eAAe,CAAC;IAChD,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC;IACtC,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC;CACvC,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC9D,CAAC"}
1
+ {"version":3,"file":"formats.js","sourceRoot":"","sources":["../src/formats.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAW3G,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAY,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAEjH,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,MAAM,CAAC,oBAAoB,EAAE,mBAAmB,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC;IAC/B,MAAM,CAAC,YAAY,EAAE,WAAW,CAAC;IACjC,MAAM,CAAC,iBAAiB,EAAE,kBAAkB,CAAC;IAC7C,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC;IACnC,MAAM,CAAC,cAAc,EAAE,aAAa,CAAC;IACrC,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;IAC9C,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;IAC9C,MAAM,CAAC,uBAAuB,EAAE,eAAe,CAAC;IAChD,MAAM,CAAC,qBAAqB,EAAE,aAAa,CAAC;IAC5C,MAAM,CAAC,uBAAuB,EAAE,eAAe,CAAC;IAChD,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC;IACtC,MAAM,CAAC,oBAAoB,EAAE,YAAY,CAAC;IAC1C,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC;CACvC,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAC9D,CAAC"}
@@ -328,6 +328,8 @@ export type components = {
328
328
  /** @description The record, once the gate is decided. */
329
329
  record?: components["schemas"]["GateRecord"];
330
330
  };
331
+ /** @description A hostname without scheme or port, for example "api.linear.app". */
332
+ Hostname: string;
331
333
  /** @description An identifier chosen by the producer. ULIDs are recommended; consumers treat it as opaque. */
332
334
  Identifier: string;
333
335
  Link: {
@@ -611,6 +613,42 @@ export type components = {
611
613
  /** @description Hostnames the sandbox may reach. Everything else is blocked. */
612
614
  egress?: string[];
613
615
  };
616
+ /** @description An MCP server that a sandbox may call over Streamable HTTP. */
617
+ SandboxMcpServer: {
618
+ /** @description The name in the egress log, for example "wiki". */
619
+ name: components["schemas"]["Name"];
620
+ /** @description The server's endpoint, for example "https://wiki.example.com/mcp". */
621
+ url: string;
622
+ /** @description The tools the sandbox may call. A call to any other tool is refused. */
623
+ tools: string[];
624
+ };
625
+ /**
626
+ * @description The input of a sandbox adapter's `create` (ADR 0054): what one sandbox runs, how much it may use, and what it may
627
+ * reach. Realizes SCN-FACTORY-RUNTIME-004, -006 and -007.
628
+ */
629
+ SandboxSpec: {
630
+ /** @description What the sandbox starts from: an image for the docker adapter, a SandboxTemplate for kubernetes, or a snapshot. */
631
+ template: string;
632
+ /** @description CPU cores. The smallest unit is 0.001 (one millicore). */
633
+ cpu?: number;
634
+ /** @description Kubernetes quantity, for example "8Gi". */
635
+ memory?: string;
636
+ /** @description Hostnames the sandbox may reach through its egress proxy. Everything else is refused. */
637
+ egress?: components["schemas"]["Hostname"][];
638
+ /** @description Variables of the sandbox's environment that hold no secret. */
639
+ env?: {
640
+ [key: string]: string;
641
+ };
642
+ /**
643
+ * @description Secrets by the name of the variable that holds the placeholder in the sandbox. The egress proxy puts the real
644
+ * value in on the way out, for the hosts of `egress`.
645
+ */
646
+ secrets?: {
647
+ [key: string]: components["schemas"]["SecretReference"];
648
+ };
649
+ /** @description The MCP servers the sandbox may call. A call to any other MCP server is refused. */
650
+ mcp?: components["schemas"]["SandboxMcpServer"][];
651
+ };
614
652
  ScenarioEvidence: {
615
653
  id: components["schemas"]["ScenarioId"];
616
654
  result: components["schemas"]["ScenarioResult"];
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export type GateRecord = Schemas["GateRecord"];
22
22
  export type GateRequest = Schemas["GateRequest"];
23
23
  export type GateView = Schemas["GateView"];
24
24
  export type ApiProblem = Schemas["ApiProblem"];
25
+ export type SandboxSpec = Schemas["SandboxSpec"];
25
26
  /** One reason a document does not match its format. `path` is a JSON Pointer into the document. */
26
27
  export interface Problem {
27
28
  path: string;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Open Software Factory contracts",
5
- "version": "1.5.0",
5
+ "version": "1.6.0",
6
6
  "description": "The shared formats as named models, and the HTTP APIs of the modules. Generated by `pnpm build` in contracts/ from typespec/. Do not edit.",
7
7
  "license": {
8
8
  "name": "Apache-2.0",
@@ -941,6 +941,11 @@
941
941
  ],
942
942
  "description": "gatekeeper: a gate as the HTTP API shows it (ADR 0048)."
943
943
  },
944
+ "Hostname": {
945
+ "type": "string",
946
+ "pattern": "^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)*$",
947
+ "description": "A hostname without scheme or port, for example \"api.linear.app\"."
948
+ },
944
949
  "Identifier": {
945
950
  "type": "string",
946
951
  "minLength": 1,
@@ -1688,6 +1693,90 @@
1688
1693
  ],
1689
1694
  "additionalProperties": false
1690
1695
  },
1696
+ "SandboxMcpServer": {
1697
+ "type": "object",
1698
+ "properties": {
1699
+ "name": {
1700
+ "$ref": "#/components/schemas/Name",
1701
+ "description": "The name in the egress log, for example \"wiki\"."
1702
+ },
1703
+ "url": {
1704
+ "type": "string",
1705
+ "pattern": "^https?://[^/]+",
1706
+ "description": "The server's endpoint, for example \"https://wiki.example.com/mcp\"."
1707
+ },
1708
+ "tools": {
1709
+ "type": "array",
1710
+ "items": {
1711
+ "type": "string"
1712
+ },
1713
+ "minItems": 1,
1714
+ "description": "The tools the sandbox may call. A call to any other tool is refused."
1715
+ }
1716
+ },
1717
+ "required": [
1718
+ "name",
1719
+ "url",
1720
+ "tools"
1721
+ ],
1722
+ "description": "An MCP server that a sandbox may call over Streamable HTTP.",
1723
+ "additionalProperties": false
1724
+ },
1725
+ "SandboxSpec": {
1726
+ "type": "object",
1727
+ "properties": {
1728
+ "template": {
1729
+ "type": "string",
1730
+ "minLength": 1,
1731
+ "description": "What the sandbox starts from: an image for the docker adapter, a SandboxTemplate for kubernetes, or a snapshot."
1732
+ },
1733
+ "cpu": {
1734
+ "type": "number",
1735
+ "minimum": 0.001,
1736
+ "description": "CPU cores. The smallest unit is 0.001 (one millicore)."
1737
+ },
1738
+ "memory": {
1739
+ "type": "string",
1740
+ "pattern": "^[0-9]+(Ki|Mi|Gi|Ti)?$",
1741
+ "description": "Kubernetes quantity, for example \"8Gi\"."
1742
+ },
1743
+ "egress": {
1744
+ "type": "array",
1745
+ "items": {
1746
+ "$ref": "#/components/schemas/Hostname"
1747
+ },
1748
+ "description": "Hostnames the sandbox may reach through its egress proxy. Everything else is refused."
1749
+ },
1750
+ "env": {
1751
+ "type": "object",
1752
+ "properties": {},
1753
+ "unevaluatedProperties": {
1754
+ "type": "string"
1755
+ },
1756
+ "description": "Variables of the sandbox's environment that hold no secret."
1757
+ },
1758
+ "secrets": {
1759
+ "type": "object",
1760
+ "properties": {},
1761
+ "unevaluatedProperties": {
1762
+ "$ref": "#/components/schemas/SecretReference"
1763
+ },
1764
+ "description": "Secrets by the name of the variable that holds the placeholder in the sandbox. The egress proxy puts the real\nvalue in on the way out, for the hosts of `egress`."
1765
+ },
1766
+ "mcp": {
1767
+ "type": "array",
1768
+ "items": {
1769
+ "$ref": "#/components/schemas/SandboxMcpServer"
1770
+ },
1771
+ "description": "The MCP servers the sandbox may call. A call to any other MCP server is refused."
1772
+ }
1773
+ },
1774
+ "required": [
1775
+ "template"
1776
+ ],
1777
+ "description": "The input of a sandbox adapter's `create` (ADR 0054): what one sandbox runs, how much it may use, and what it may\nreach. Realizes SCN-FACTORY-RUNTIME-004, -006 and -007.",
1778
+ "additionalProperties": false
1779
+ },
1691
1780
  "ScenarioEvidence": {
1692
1781
  "type": "object",
1693
1782
  "properties": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensoftware/contracts",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "The shared formats of the open software factory: JSON Schemas, TypeScript types and the osf-contracts CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -44,7 +44,7 @@
44
44
  "@typespec/openapi": "1.17.0",
45
45
  "@typespec/openapi3": "1.17.0",
46
46
  "openapi-typescript": "7.13.0",
47
- "@opensoftware/testkit": "0.12.0"
47
+ "@opensoftware/testkit": "0.16.0"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "node scripts/build.ts",
@@ -0,0 +1,90 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/sesigl/open-software-factory/main/contracts/sandbox-spec/sandbox-spec.schema.json",
4
+ "title": "SandboxSpec",
5
+ "$comment": "Generated by `pnpm build` in contracts/ from typespec/. Do not edit.",
6
+ "type": "object",
7
+ "properties": {
8
+ "template": {
9
+ "type": "string",
10
+ "minLength": 1,
11
+ "description": "What the sandbox starts from: an image for the docker adapter, a SandboxTemplate for kubernetes, or a snapshot."
12
+ },
13
+ "cpu": {
14
+ "type": "number",
15
+ "minimum": 0.001,
16
+ "description": "CPU cores. The smallest unit is 0.001 (one millicore)."
17
+ },
18
+ "memory": {
19
+ "type": "string",
20
+ "pattern": "^[0-9]+(Ki|Mi|Gi|Ti)?$",
21
+ "description": "Kubernetes quantity, for example \"8Gi\"."
22
+ },
23
+ "egress": {
24
+ "type": "array",
25
+ "items": {
26
+ "type": "string",
27
+ "pattern": "^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)*$",
28
+ "description": "A hostname without scheme or port, for example \"api.linear.app\"."
29
+ },
30
+ "description": "Hostnames the sandbox may reach through its egress proxy. Everything else is refused."
31
+ },
32
+ "env": {
33
+ "type": "object",
34
+ "properties": {},
35
+ "unevaluatedProperties": {
36
+ "type": "string"
37
+ },
38
+ "description": "Variables of the sandbox's environment that hold no secret."
39
+ },
40
+ "secrets": {
41
+ "type": "object",
42
+ "properties": {},
43
+ "unevaluatedProperties": {
44
+ "type": "string",
45
+ "pattern": "^ref:[a-z][a-z0-9-]*/[A-Za-z0-9_./-]+$",
46
+ "description": "A reference to a secret, resolved at the egress proxy, never in the sandbox: \"ref:<provider>/<name>\"."
47
+ },
48
+ "description": "Secrets by the name of the variable that holds the placeholder in the sandbox. The egress proxy puts the real\nvalue in on the way out, for the hosts of `egress`."
49
+ },
50
+ "mcp": {
51
+ "type": "array",
52
+ "items": {
53
+ "type": "object",
54
+ "properties": {
55
+ "name": {
56
+ "type": "string",
57
+ "pattern": "^[a-z][a-z0-9-]{0,62}$",
58
+ "description": "The name in the egress log, for example \"wiki\"."
59
+ },
60
+ "url": {
61
+ "type": "string",
62
+ "pattern": "^https?://[^/]+",
63
+ "description": "The server's endpoint, for example \"https://wiki.example.com/mcp\"."
64
+ },
65
+ "tools": {
66
+ "type": "array",
67
+ "items": {
68
+ "type": "string"
69
+ },
70
+ "minItems": 1,
71
+ "description": "The tools the sandbox may call. A call to any other tool is refused."
72
+ }
73
+ },
74
+ "required": [
75
+ "name",
76
+ "url",
77
+ "tools"
78
+ ],
79
+ "description": "An MCP server that a sandbox may call over Streamable HTTP.",
80
+ "additionalProperties": false
81
+ },
82
+ "description": "The MCP servers the sandbox may call. A call to any other MCP server is refused."
83
+ }
84
+ },
85
+ "required": [
86
+ "template"
87
+ ],
88
+ "description": "The input of a sandbox adapter's `create` (ADR 0054): what one sandbox runs, how much it may use, and what it may\nreach. Realizes SCN-FACTORY-RUNTIME-004, -006 and -007.",
89
+ "additionalProperties": false
90
+ }
package/typespec/main.tsp CHANGED
@@ -10,3 +10,4 @@ import "./score.tsp";
10
10
  import "./events.tsp";
11
11
  import "./gatekeeper.tsp";
12
12
  import "./gatekeeper-api.tsp";
13
+ import "./sandbox.tsp";
@@ -0,0 +1,63 @@
1
+ import "@typespec/json-schema";
2
+ import "./common.tsp";
3
+ import "./factory-definition.tsp";
4
+
5
+ using TypeSpec.JsonSchema;
6
+
7
+ namespace Osf.Contracts;
8
+
9
+ // The sandbox spec is written by a program (foreman) for a sandbox adapter, and a sandbox must never get more than
10
+ // it asked for: every object is closed, so an unknown field is an error and not a silent grant.
11
+
12
+ /**
13
+ * The input of a sandbox adapter's `create` (ADR 0054): what one sandbox runs, how much it may use, and what it may
14
+ * reach. Realizes SCN-FACTORY-RUNTIME-004, -006 and -007.
15
+ */
16
+ @extension("additionalProperties", Json<false>)
17
+ model SandboxSpec {
18
+ /** What the sandbox starts from: an image for the docker adapter, a SandboxTemplate for kubernetes, or a snapshot. */
19
+ @minLength(1)
20
+ template: string;
21
+
22
+ /** CPU cores. The smallest unit is 0.001 (one millicore). */
23
+ @minValue(0.001)
24
+ cpu?: float64;
25
+
26
+ /** Kubernetes quantity, for example "8Gi". */
27
+ @pattern("^[0-9]+(Ki|Mi|Gi|Ti)?$")
28
+ memory?: string;
29
+
30
+ /** Hostnames the sandbox may reach through its egress proxy. Everything else is refused. */
31
+ egress?: Hostname[];
32
+
33
+ /** Variables of the sandbox's environment that hold no secret. */
34
+ env?: Record<string>;
35
+
36
+ /**
37
+ * Secrets by the name of the variable that holds the placeholder in the sandbox. The egress proxy puts the real
38
+ * value in on the way out, for the hosts of `egress`.
39
+ */
40
+ secrets?: Record<SecretReference>;
41
+
42
+ /** The MCP servers the sandbox may call. A call to any other MCP server is refused. */
43
+ mcp?: SandboxMcpServer[];
44
+ }
45
+
46
+ /** A hostname without scheme or port, for example "api.linear.app". */
47
+ @pattern("^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)*$")
48
+ scalar Hostname extends string;
49
+
50
+ /** An MCP server that a sandbox may call over Streamable HTTP. */
51
+ @extension("additionalProperties", Json<false>)
52
+ model SandboxMcpServer {
53
+ /** The name in the egress log, for example "wiki". */
54
+ name: Name;
55
+
56
+ /** The server's endpoint, for example "https://wiki.example.com/mcp". */
57
+ @pattern("^https?://[^/]+")
58
+ url: string;
59
+
60
+ /** The tools the sandbox may call. A call to any other tool is refused. */
61
+ @minItems(1)
62
+ tools: string[];
63
+ }