@sealant/api-contracts-next 0.39.0-next.712 → 0.39.0-next.714
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/dist/core-api/control-plane.d.ts +735 -709
- package/dist/core-api/system.d.ts +14 -0
- package/dist/core-api/system.js +7 -0
- package/dist/core-api/users.d.ts +49 -1
- package/dist/core-api/users.js +37 -0
- package/dist/core-api/workspaces.d.ts +73 -2
- package/dist/core-api/workspaces.js +50 -0
- package/package.json +2 -2
|
@@ -33,6 +33,13 @@ export declare const systemIndexResponseSchema: Schema.Struct<{
|
|
|
33
33
|
readonly credentialsPiOpencode: Schema.optional<Schema.Boolean>;
|
|
34
34
|
/** `ownerMap` on a capture source: an executor whose restore gives each person their files. */
|
|
35
35
|
readonly captureOwnerMap: Schema.optional<Schema.Boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* `sshAsOwner` on a create and `DELETE /v1/workspaces/:id/ssh-user`: the SSH gateway runs a
|
|
38
|
+
* workspace's SSH sessions as its owner's own Linux user (their `credentialsHome` uid).
|
|
39
|
+
*/
|
|
40
|
+
readonly workspaceSshUser: Schema.optional<Schema.Boolean>;
|
|
41
|
+
/** `POST /v1/users/:id/person`: a user's person bound once (what `sshAsOwner` checks). */
|
|
42
|
+
readonly personBinding: Schema.optional<Schema.Boolean>;
|
|
36
43
|
}>>;
|
|
37
44
|
}>;
|
|
38
45
|
export type SystemIndexResponse = typeof systemIndexResponseSchema.Type;
|
|
@@ -93,6 +100,13 @@ export declare const SystemGroup: HttpApiGroup.HttpApiGroup<"system", HttpApiEnd
|
|
|
93
100
|
readonly credentialsPiOpencode: Schema.optional<Schema.Boolean>;
|
|
94
101
|
/** `ownerMap` on a capture source: an executor whose restore gives each person their files. */
|
|
95
102
|
readonly captureOwnerMap: Schema.optional<Schema.Boolean>;
|
|
103
|
+
/**
|
|
104
|
+
* `sshAsOwner` on a create and `DELETE /v1/workspaces/:id/ssh-user`: the SSH gateway runs a
|
|
105
|
+
* workspace's SSH sessions as its owner's own Linux user (their `credentialsHome` uid).
|
|
106
|
+
*/
|
|
107
|
+
readonly workspaceSshUser: Schema.optional<Schema.Boolean>;
|
|
108
|
+
/** `POST /v1/users/:id/person`: a user's person bound once (what `sshAsOwner` checks). */
|
|
109
|
+
readonly personBinding: Schema.optional<Schema.Boolean>;
|
|
96
110
|
}>>;
|
|
97
111
|
}>>, HttpApiEndpoint.Json<never>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"getSetupState", "GET", "/v1/system/setup-state", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
98
112
|
readonly needsSetup: Schema.Boolean;
|
package/dist/core-api/system.js
CHANGED
|
@@ -34,6 +34,13 @@ export const systemIndexResponseSchema = Schema.Struct({
|
|
|
34
34
|
credentialsPiOpencode: Schema.optional(Schema.Boolean),
|
|
35
35
|
/** `ownerMap` on a capture source: an executor whose restore gives each person their files. */
|
|
36
36
|
captureOwnerMap: Schema.optional(Schema.Boolean),
|
|
37
|
+
/**
|
|
38
|
+
* `sshAsOwner` on a create and `DELETE /v1/workspaces/:id/ssh-user`: the SSH gateway runs a
|
|
39
|
+
* workspace's SSH sessions as its owner's own Linux user (their `credentialsHome` uid).
|
|
40
|
+
*/
|
|
41
|
+
workspaceSshUser: Schema.optional(Schema.Boolean),
|
|
42
|
+
/** `POST /v1/users/:id/person`: a user's person bound once (what `sshAsOwner` checks). */
|
|
43
|
+
personBinding: Schema.optional(Schema.Boolean),
|
|
37
44
|
})),
|
|
38
45
|
});
|
|
39
46
|
export const systemHealthResponseSchema = Schema.Struct({
|
package/dist/core-api/users.d.ts
CHANGED
|
@@ -32,6 +32,39 @@ export declare const ensureUserResponseSchema: Schema.Struct<{
|
|
|
32
32
|
readonly created: Schema.Boolean;
|
|
33
33
|
}>;
|
|
34
34
|
export type EnsureUserResponse = typeof ensureUserResponseSchema.Type;
|
|
35
|
+
/**
|
|
36
|
+
* The person a user is (Mend ADR 0016: a person's Linux identity, the same in every workspace):
|
|
37
|
+
* their id in a capture owner map, their uid (40001–49999) and their home, an absolute normalised
|
|
38
|
+
* path under the deployment's homes root (`SEALANT_PERSON_HOMES_ROOT`, default `/home`).
|
|
39
|
+
*/
|
|
40
|
+
export declare const personBindingSchema: Schema.Struct<{
|
|
41
|
+
readonly id: Schema.String;
|
|
42
|
+
readonly uid: Schema.Int;
|
|
43
|
+
readonly home: Schema.String;
|
|
44
|
+
}>;
|
|
45
|
+
export type PersonBindingWire = typeof personBindingSchema.Type;
|
|
46
|
+
export declare const bindUserPersonResponseSchema: Schema.Struct<{
|
|
47
|
+
readonly userId: Schema.String;
|
|
48
|
+
readonly person: Schema.Struct<{
|
|
49
|
+
readonly id: Schema.String;
|
|
50
|
+
readonly uid: Schema.Int;
|
|
51
|
+
readonly home: Schema.String;
|
|
52
|
+
}>;
|
|
53
|
+
/** True when this call made the binding; false when it was already exactly this. */
|
|
54
|
+
readonly created: Schema.Boolean;
|
|
55
|
+
}>;
|
|
56
|
+
export type BindUserPersonResponse = typeof bindUserPersonResponseSchema.Type;
|
|
57
|
+
declare const UserPersonConflictError_base: Schema.Class<UserPersonConflictError, Schema.TaggedStruct<"UserPersonConflictError", {
|
|
58
|
+
readonly message: Schema.String;
|
|
59
|
+
readonly code: Schema.Literals<readonly ["person-binding-differs", "person-taken"]>;
|
|
60
|
+
}>, import("effect/Cause").YieldableError>;
|
|
61
|
+
/**
|
|
62
|
+
* A binding that would change one already made: the user is bound to another person
|
|
63
|
+
* (`person-binding-differs`), or the person id or uid is another user's (`person-taken`). A
|
|
64
|
+
* binding is never changed through the API; the answer names no other user's values.
|
|
65
|
+
*/
|
|
66
|
+
export declare class UserPersonConflictError extends UserPersonConflictError_base {
|
|
67
|
+
}
|
|
35
68
|
declare const UserBadRequestError_base: Schema.Class<UserBadRequestError, Schema.TaggedStruct<"UserBadRequestError", {
|
|
36
69
|
readonly message: Schema.String;
|
|
37
70
|
}>, import("effect/Cause").YieldableError>;
|
|
@@ -47,7 +80,22 @@ declare const UserInternalServerError_base: Schema.Class<UserInternalServerError
|
|
|
47
80
|
}>, import("effect/Cause").YieldableError>;
|
|
48
81
|
export declare class UserInternalServerError extends UserInternalServerError_base {
|
|
49
82
|
}
|
|
50
|
-
export declare const UsersGroup: HttpApiGroup.HttpApiGroup<"users", HttpApiEndpoint.HttpApiEndpoint<"
|
|
83
|
+
export declare const UsersGroup: HttpApiGroup.HttpApiGroup<"users", HttpApiEndpoint.HttpApiEndpoint<"bindUserPerson", "POST", "/:userId/person", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
84
|
+
readonly userId: Schema.String;
|
|
85
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
86
|
+
readonly id: Schema.String;
|
|
87
|
+
readonly uid: Schema.Int;
|
|
88
|
+
readonly home: Schema.String;
|
|
89
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
90
|
+
readonly userId: Schema.String;
|
|
91
|
+
readonly person: Schema.Struct<{
|
|
92
|
+
readonly id: Schema.String;
|
|
93
|
+
readonly uid: Schema.Int;
|
|
94
|
+
readonly home: Schema.String;
|
|
95
|
+
}>;
|
|
96
|
+
/** True when this call made the binding; false when it was already exactly this. */
|
|
97
|
+
readonly created: Schema.Boolean;
|
|
98
|
+
}>>, HttpApiEndpoint.Json<typeof UserPersonConflictError | typeof UserBadRequestError | typeof UserNotFoundError | typeof UserInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"ensureUser", "POST", "/", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
51
99
|
/** Matched case-insensitively; the stored form is lower-cased. */
|
|
52
100
|
readonly email: Schema.String;
|
|
53
101
|
readonly name: Schema.String;
|
package/dist/core-api/users.js
CHANGED
|
@@ -27,6 +27,32 @@ export const ensureUserResponseSchema = Schema.Struct({
|
|
|
27
27
|
/** True when this call created the user. */
|
|
28
28
|
created: Schema.Boolean,
|
|
29
29
|
});
|
|
30
|
+
/**
|
|
31
|
+
* The person a user is (Mend ADR 0016: a person's Linux identity, the same in every workspace):
|
|
32
|
+
* their id in a capture owner map, their uid (40001–49999) and their home, an absolute normalised
|
|
33
|
+
* path under the deployment's homes root (`SEALANT_PERSON_HOMES_ROOT`, default `/home`).
|
|
34
|
+
*/
|
|
35
|
+
export const personBindingSchema = Schema.Struct({
|
|
36
|
+
id: NonEmptyString,
|
|
37
|
+
uid: Schema.Int,
|
|
38
|
+
home: NonEmptyString,
|
|
39
|
+
});
|
|
40
|
+
export const bindUserPersonResponseSchema = Schema.Struct({
|
|
41
|
+
userId: NonEmptyString,
|
|
42
|
+
person: personBindingSchema,
|
|
43
|
+
/** True when this call made the binding; false when it was already exactly this. */
|
|
44
|
+
created: Schema.Boolean,
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* A binding that would change one already made: the user is bound to another person
|
|
48
|
+
* (`person-binding-differs`), or the person id or uid is another user's (`person-taken`). A
|
|
49
|
+
* binding is never changed through the API; the answer names no other user's values.
|
|
50
|
+
*/
|
|
51
|
+
export class UserPersonConflictError extends Schema.TaggedErrorClass()("UserPersonConflictError", {
|
|
52
|
+
message: Schema.String,
|
|
53
|
+
code: Schema.Literals(["person-binding-differs", "person-taken"]),
|
|
54
|
+
}, { httpApiStatus: 409 }) {
|
|
55
|
+
}
|
|
30
56
|
export class UserBadRequestError extends Schema.TaggedErrorClass()("UserBadRequestError", { message: Schema.String }, { httpApiStatus: 400 }) {
|
|
31
57
|
}
|
|
32
58
|
export class UserNotFoundError extends Schema.TaggedErrorClass()("UserNotFoundError", { message: Schema.String }, { httpApiStatus: 404 }) {
|
|
@@ -39,6 +65,17 @@ export const UsersGroup = HttpApiGroup.make("users")
|
|
|
39
65
|
payload: ensureUserRequestSchema,
|
|
40
66
|
success: ensureUserResponseSchema,
|
|
41
67
|
error: [UserBadRequestError, UserInternalServerError],
|
|
68
|
+
}))
|
|
69
|
+
.add(HttpApiEndpoint.post("bindUserPerson", "/:userId/person", {
|
|
70
|
+
params: userIdParams,
|
|
71
|
+
payload: personBindingSchema,
|
|
72
|
+
success: bindUserPersonResponseSchema,
|
|
73
|
+
error: [
|
|
74
|
+
UserBadRequestError,
|
|
75
|
+
UserNotFoundError,
|
|
76
|
+
UserPersonConflictError,
|
|
77
|
+
UserInternalServerError,
|
|
78
|
+
],
|
|
42
79
|
}))
|
|
43
80
|
.add(HttpApiEndpoint.get("getUser", "/:userId", {
|
|
44
81
|
params: userIdParams,
|
|
@@ -45,6 +45,14 @@ export declare const workspaceSshTargetSchema: Schema.Struct<{
|
|
|
45
45
|
readonly status: Schema.Literals<readonly ["pending", "running", "ready", "failed", "stopped"]>;
|
|
46
46
|
readonly endpoint: Schema.String;
|
|
47
47
|
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Who the gateway runs this workspace's SSH sessions as, always stated: the workspace owner's
|
|
50
|
+
* Linux user (a decimal uid, from the owner's `credentialsHome`), or `null` for root. A gateway
|
|
51
|
+
* refuses a target that does not state it (an older API, which knows no SSH user), never reads
|
|
52
|
+
* the silence as root. Sent only to a gateway that says it runs sessions as a user
|
|
53
|
+
* (`x-sealant-gateway-ssh-user: 1`); a workspace with a user refuses any other gateway.
|
|
54
|
+
*/
|
|
55
|
+
readonly sessionUser: Schema.NullOr<Schema.String>;
|
|
48
56
|
}>;
|
|
49
57
|
export type WorkspaceSshTarget = typeof workspaceSshTargetSchema.Type;
|
|
50
58
|
/**
|
|
@@ -160,6 +168,15 @@ export declare const createWorkspaceRequestSchema: Schema.Struct<{
|
|
|
160
168
|
* completion attestation that names a launch must name this one.
|
|
161
169
|
*/
|
|
162
170
|
readonly launchId: Schema.optional<Schema.String>;
|
|
171
|
+
/**
|
|
172
|
+
* The SSH gateway runs this workspace's SSH sessions as its owner's own Linux user: the person
|
|
173
|
+
* the owner is bound to (`POST /v1/users/:id/person`). The create must carry a capture owner map
|
|
174
|
+
* giving that person their bound uid, and `runtime.credentialsHome` must be their bound uid and
|
|
175
|
+
* home; otherwise 403 (`WorkspaceSshOwnerRefusedError`). The caller names no user. The user need not exist
|
|
176
|
+
* yet: until it does, an SSH session is refused, never run as root. Absent or false: root. A
|
|
177
|
+
* control plane reports it takes this with `features.workspaceSshUser`; an older one ignores it.
|
|
178
|
+
*/
|
|
179
|
+
readonly sshAsOwner: Schema.optional<Schema.Boolean>;
|
|
163
180
|
}>;
|
|
164
181
|
export type CreateWorkspaceRequest = typeof createWorkspaceRequestSchema.Type;
|
|
165
182
|
export declare const createWorkspaceHeadersSchema: Schema.Struct<{
|
|
@@ -579,6 +596,15 @@ export declare const renameWorkspaceRequestSchema: Schema.Struct<{
|
|
|
579
596
|
readonly ownerUserId: Schema.optional<Schema.String>;
|
|
580
597
|
}>;
|
|
581
598
|
export type RenameWorkspaceRequest = typeof renameWorkspaceRequestSchema.Type;
|
|
599
|
+
/**
|
|
600
|
+
* `DELETE /v1/workspaces/:id/ssh-user`: the gateway runs the workspace's SSH sessions as root from
|
|
601
|
+
* the next session channel on. The only change after create: no caller ever names a user.
|
|
602
|
+
*/
|
|
603
|
+
export declare const clearWorkspaceSshUserQuerySchema: Schema.Struct<{
|
|
604
|
+
/** The workspace's owner. Required by the control plane: a request that names none finds nothing. */
|
|
605
|
+
readonly ownerUserId: Schema.optional<Schema.String>;
|
|
606
|
+
}>;
|
|
607
|
+
export type ClearWorkspaceSshUserQuery = typeof clearWorkspaceSshUserQuerySchema.Type;
|
|
582
608
|
export declare const stopWorkspaceRequestSchema: Schema.Struct<{
|
|
583
609
|
readonly ownerUserId: Schema.String;
|
|
584
610
|
/**
|
|
@@ -1007,6 +1033,12 @@ export declare const renameWorkspaceResponseSchema: Schema.Struct<{
|
|
|
1007
1033
|
readonly updatedAt: Schema.String;
|
|
1008
1034
|
}>;
|
|
1009
1035
|
export type RenameWorkspaceResponse = typeof renameWorkspaceResponseSchema.Type;
|
|
1036
|
+
export declare const clearWorkspaceSshUserResponseSchema: Schema.Struct<{
|
|
1037
|
+
readonly workspaceId: Schema.String;
|
|
1038
|
+
/** Always `null` (root) after the call. */
|
|
1039
|
+
readonly sshUser: Schema.Null;
|
|
1040
|
+
}>;
|
|
1041
|
+
export type ClearWorkspaceSshUserResponse = typeof clearWorkspaceSshUserResponseSchema.Type;
|
|
1010
1042
|
export declare const createWorkspaceResponseSchema: Schema.Struct<{
|
|
1011
1043
|
readonly workspaceId: Schema.String;
|
|
1012
1044
|
readonly name: Schema.String;
|
|
@@ -1676,6 +1708,7 @@ export type ListWorkspaceEventsResponse = typeof listWorkspaceEventsResponseSche
|
|
|
1676
1708
|
export declare const workspaceGatewayHeadersSchema: Schema.Struct<{
|
|
1677
1709
|
readonly "x-sealant-gateway-token": Schema.optional<Schema.String>;
|
|
1678
1710
|
readonly "x-sealant-principal-id": Schema.optional<Schema.String>;
|
|
1711
|
+
readonly "x-sealant-gateway-ssh-user": Schema.optional<Schema.String>;
|
|
1679
1712
|
}>;
|
|
1680
1713
|
export type WorkspaceGatewayHeaders = typeof workspaceGatewayHeadersSchema.Type;
|
|
1681
1714
|
declare const WorkspaceBadRequestError_base: Schema.Class<WorkspaceBadRequestError, Schema.TaggedStruct<"WorkspaceBadRequestError", {
|
|
@@ -1714,6 +1747,17 @@ declare const WorkspaceUnauthorizedError_base: Schema.Class<WorkspaceUnauthorize
|
|
|
1714
1747
|
}>, import("effect/Cause").YieldableError>;
|
|
1715
1748
|
export declare class WorkspaceUnauthorizedError extends WorkspaceUnauthorizedError_base {
|
|
1716
1749
|
}
|
|
1750
|
+
declare const WorkspaceSshOwnerRefusedError_base: Schema.Class<WorkspaceSshOwnerRefusedError, Schema.TaggedStruct<"WorkspaceSshOwnerRefusedError", {
|
|
1751
|
+
readonly message: Schema.String;
|
|
1752
|
+
readonly code: Schema.Literals<readonly ["ssh-owner-unbound", "ssh-owner-needs-owner-map", "ssh-owner-mismatch"]>;
|
|
1753
|
+
}>, import("effect/Cause").YieldableError>;
|
|
1754
|
+
/**
|
|
1755
|
+
* `sshAsOwner` refused: the owner is bound to no person (`ssh-owner-unbound`), the create carries no
|
|
1756
|
+
* capture owner map (`ssh-owner-needs-owner-map`), or the owner map or `credentialsHome` does not
|
|
1757
|
+
* give the owner's bound person their own uid and home (`ssh-owner-mismatch`). Names no path.
|
|
1758
|
+
*/
|
|
1759
|
+
export declare class WorkspaceSshOwnerRefusedError extends WorkspaceSshOwnerRefusedError_base {
|
|
1760
|
+
}
|
|
1717
1761
|
declare const WorkspaceForbiddenError_base: Schema.Class<WorkspaceForbiddenError, Schema.TaggedStruct<"WorkspaceForbiddenError", {
|
|
1718
1762
|
readonly message: Schema.String;
|
|
1719
1763
|
}>, import("effect/Cause").YieldableError>;
|
|
@@ -1830,7 +1874,16 @@ export declare const WorkspacesGroup: HttpApiGroup.HttpApiGroup<"workspaces", Ht
|
|
|
1830
1874
|
readonly workspaceId: Schema.optional<Schema.String>;
|
|
1831
1875
|
readonly runId: Schema.optional<Schema.String>;
|
|
1832
1876
|
readonly launchId: Schema.optional<Schema.String>;
|
|
1833
|
-
}>>, HttpApiEndpoint.Json<typeof WorkspaceBadRequestError | typeof WorkspaceInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"
|
|
1877
|
+
}>>, HttpApiEndpoint.Json<typeof WorkspaceBadRequestError | typeof WorkspaceInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"clearWorkspaceSshUser", "DELETE", "/:workspaceId/ssh-user", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
1878
|
+
readonly workspaceId: Schema.String;
|
|
1879
|
+
}>>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
1880
|
+
/** The workspace's owner. Required by the control plane: a request that names none finds nothing. */
|
|
1881
|
+
readonly ownerUserId: Schema.optional<Schema.String>;
|
|
1882
|
+
}>>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
1883
|
+
readonly workspaceId: Schema.String;
|
|
1884
|
+
/** Always `null` (root) after the call. */
|
|
1885
|
+
readonly sshUser: Schema.Null;
|
|
1886
|
+
}>>, HttpApiEndpoint.Json<typeof WorkspaceNotFoundError | typeof WorkspaceInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"createWorkspace", "POST", "/", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
1834
1887
|
readonly ownerUserId: Schema.String;
|
|
1835
1888
|
readonly registryId: Schema.String;
|
|
1836
1889
|
readonly repository: Schema.String;
|
|
@@ -1873,6 +1926,15 @@ export declare const WorkspacesGroup: HttpApiGroup.HttpApiGroup<"workspaces", Ht
|
|
|
1873
1926
|
* completion attestation that names a launch must name this one.
|
|
1874
1927
|
*/
|
|
1875
1928
|
readonly launchId: Schema.optional<Schema.String>;
|
|
1929
|
+
/**
|
|
1930
|
+
* The SSH gateway runs this workspace's SSH sessions as its owner's own Linux user: the person
|
|
1931
|
+
* the owner is bound to (`POST /v1/users/:id/person`). The create must carry a capture owner map
|
|
1932
|
+
* giving that person their bound uid, and `runtime.credentialsHome` must be their bound uid and
|
|
1933
|
+
* home; otherwise 403 (`WorkspaceSshOwnerRefusedError`). The caller names no user. The user need not exist
|
|
1934
|
+
* yet: until it does, an SSH session is refused, never run as root. Absent or false: root. A
|
|
1935
|
+
* control plane reports it takes this with `features.workspaceSshUser`; an older one ignores it.
|
|
1936
|
+
*/
|
|
1937
|
+
readonly sshAsOwner: Schema.optional<Schema.Boolean>;
|
|
1876
1938
|
}>>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
1877
1939
|
readonly "idempotency-key": Schema.optional<Schema.String>;
|
|
1878
1940
|
}>>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
@@ -1915,7 +1977,7 @@ export declare const WorkspacesGroup: HttpApiGroup.HttpApiGroup<"workspaces", Ht
|
|
|
1915
1977
|
readonly replayed: Schema.optional<Schema.Boolean>;
|
|
1916
1978
|
/** The launch identity the create named (`launchId`), recorded on its attempt. */
|
|
1917
1979
|
readonly launchId: Schema.optional<Schema.String>;
|
|
1918
|
-
}>>, HttpApiEndpoint.Json<typeof BudgetExceededError | typeof WorkspaceBadRequestError | typeof WorkspaceRuntimeEnvReferencesUnsupportedError | typeof WorkspaceDockerServiceUnsupportedError | typeof WorkspaceForbiddenError | typeof WorkspaceNotFoundError | typeof WorkspaceConflictError | typeof WorkspaceBadGatewayError | typeof WorkspaceServiceUnavailableError | typeof WorkspaceInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"execWorkspace", "POST", "/:workspaceId/exec", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
1980
|
+
}>>, HttpApiEndpoint.Json<typeof BudgetExceededError | typeof WorkspaceBadRequestError | typeof WorkspaceRuntimeEnvReferencesUnsupportedError | typeof WorkspaceDockerServiceUnsupportedError | typeof WorkspaceSshOwnerRefusedError | typeof WorkspaceForbiddenError | typeof WorkspaceNotFoundError | typeof WorkspaceConflictError | typeof WorkspaceBadGatewayError | typeof WorkspaceServiceUnavailableError | typeof WorkspaceInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"execWorkspace", "POST", "/:workspaceId/exec", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
1919
1981
|
readonly workspaceId: Schema.String;
|
|
1920
1982
|
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
1921
1983
|
readonly ownerUserId: Schema.String;
|
|
@@ -2429,6 +2491,7 @@ export declare const WorkspacesGroup: HttpApiGroup.HttpApiGroup<"workspaces", Ht
|
|
|
2429
2491
|
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
2430
2492
|
readonly "x-sealant-gateway-token": Schema.optional<Schema.String>;
|
|
2431
2493
|
readonly "x-sealant-principal-id": Schema.optional<Schema.String>;
|
|
2494
|
+
readonly "x-sealant-gateway-ssh-user": Schema.optional<Schema.String>;
|
|
2432
2495
|
}>>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
2433
2496
|
readonly workspaceId: Schema.String;
|
|
2434
2497
|
readonly attemptId: Schema.String;
|
|
@@ -2439,6 +2502,14 @@ export declare const WorkspacesGroup: HttpApiGroup.HttpApiGroup<"workspaces", Ht
|
|
|
2439
2502
|
readonly status: Schema.Literals<readonly ["pending", "running", "ready", "failed", "stopped"]>;
|
|
2440
2503
|
readonly endpoint: Schema.String;
|
|
2441
2504
|
}>;
|
|
2505
|
+
/**
|
|
2506
|
+
* Who the gateway runs this workspace's SSH sessions as, always stated: the workspace owner's
|
|
2507
|
+
* Linux user (a decimal uid, from the owner's `credentialsHome`), or `null` for root. A gateway
|
|
2508
|
+
* refuses a target that does not state it (an older API, which knows no SSH user), never reads
|
|
2509
|
+
* the silence as root. Sent only to a gateway that says it runs sessions as a user
|
|
2510
|
+
* (`x-sealant-gateway-ssh-user: 1`); a workspace with a user refuses any other gateway.
|
|
2511
|
+
*/
|
|
2512
|
+
readonly sessionUser: Schema.NullOr<Schema.String>;
|
|
2442
2513
|
}>>, HttpApiEndpoint.Json<typeof WorkspaceUnauthorizedError | typeof WorkspaceNotFoundError | typeof WorkspaceConflictError | typeof WorkspaceServiceUnavailableError | typeof WorkspaceInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"inspectWorkspaceImage", "POST", "/image", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
2443
2514
|
readonly ownerUserId: Schema.String;
|
|
2444
2515
|
readonly registryId: Schema.String;
|
|
@@ -55,6 +55,14 @@ export const workspaceSshTargetSchema = Schema.Struct({
|
|
|
55
55
|
status: Schema.Literals(["pending", "running", "ready", "failed", "stopped"]),
|
|
56
56
|
endpoint: Schema.String,
|
|
57
57
|
}),
|
|
58
|
+
/**
|
|
59
|
+
* Who the gateway runs this workspace's SSH sessions as, always stated: the workspace owner's
|
|
60
|
+
* Linux user (a decimal uid, from the owner's `credentialsHome`), or `null` for root. A gateway
|
|
61
|
+
* refuses a target that does not state it (an older API, which knows no SSH user), never reads
|
|
62
|
+
* the silence as root. Sent only to a gateway that says it runs sessions as a user
|
|
63
|
+
* (`x-sealant-gateway-ssh-user: 1`); a workspace with a user refuses any other gateway.
|
|
64
|
+
*/
|
|
65
|
+
sessionUser: Schema.NullOr(NonEmptyString),
|
|
58
66
|
});
|
|
59
67
|
/**
|
|
60
68
|
* Whether an image can run Mend's per-person layout on a runtime (Mend ADR 0016): the verdict of
|
|
@@ -154,6 +162,15 @@ export const createWorkspaceRequestSchema = Schema.Struct({
|
|
|
154
162
|
* completion attestation that names a launch must name this one.
|
|
155
163
|
*/
|
|
156
164
|
launchId: Schema.optional(NonEmptyString),
|
|
165
|
+
/**
|
|
166
|
+
* The SSH gateway runs this workspace's SSH sessions as its owner's own Linux user: the person
|
|
167
|
+
* the owner is bound to (`POST /v1/users/:id/person`). The create must carry a capture owner map
|
|
168
|
+
* giving that person their bound uid, and `runtime.credentialsHome` must be their bound uid and
|
|
169
|
+
* home; otherwise 403 (`WorkspaceSshOwnerRefusedError`). The caller names no user. The user need not exist
|
|
170
|
+
* yet: until it does, an SSH session is refused, never run as root. Absent or false: root. A
|
|
171
|
+
* control plane reports it takes this with `features.workspaceSshUser`; an older one ignores it.
|
|
172
|
+
*/
|
|
173
|
+
sshAsOwner: Schema.optional(Schema.Boolean),
|
|
157
174
|
});
|
|
158
175
|
export const createWorkspaceHeadersSchema = Schema.Struct({
|
|
159
176
|
"idempotency-key": Schema.optional(NonEmptyString),
|
|
@@ -507,6 +524,14 @@ export const renameWorkspaceRequestSchema = Schema.Struct({
|
|
|
507
524
|
/** The workspace's owner. Required by the control plane: a rename that names none finds nothing. */
|
|
508
525
|
ownerUserId: Schema.optional(NonEmptyString),
|
|
509
526
|
});
|
|
527
|
+
/**
|
|
528
|
+
* `DELETE /v1/workspaces/:id/ssh-user`: the gateway runs the workspace's SSH sessions as root from
|
|
529
|
+
* the next session channel on. The only change after create: no caller ever names a user.
|
|
530
|
+
*/
|
|
531
|
+
export const clearWorkspaceSshUserQuerySchema = Schema.Struct({
|
|
532
|
+
/** The workspace's owner. Required by the control plane: a request that names none finds nothing. */
|
|
533
|
+
ownerUserId: Schema.optional(NonEmptyString),
|
|
534
|
+
});
|
|
510
535
|
// Lifecycle actions are owner-scoped like execWorkspace: ownerUserId rides in the payload and a
|
|
511
536
|
// mismatch yields a uniform 404 (existence is not leaked).
|
|
512
537
|
export const stopWorkspaceRequestSchema = Schema.Struct({
|
|
@@ -797,6 +822,11 @@ export const renameWorkspaceResponseSchema = Schema.Struct({
|
|
|
797
822
|
name: NonEmptyString,
|
|
798
823
|
updatedAt: Schema.String,
|
|
799
824
|
});
|
|
825
|
+
export const clearWorkspaceSshUserResponseSchema = Schema.Struct({
|
|
826
|
+
workspaceId: NonEmptyString,
|
|
827
|
+
/** Always `null` (root) after the call. */
|
|
828
|
+
sshUser: Schema.Null,
|
|
829
|
+
});
|
|
800
830
|
export const createWorkspaceResponseSchema = Schema.Struct({
|
|
801
831
|
workspaceId: NonEmptyString,
|
|
802
832
|
name: NonEmptyString,
|
|
@@ -1072,6 +1102,9 @@ export const workspaceGatewayHeadersSchema = Schema.Struct({
|
|
|
1072
1102
|
// Identifies the client principal (the SSH key's owner). The API authorizes principal x workspace
|
|
1073
1103
|
// before returning a control target (gateway-spec §3.4).
|
|
1074
1104
|
"x-sealant-principal-id": Schema.optional(NonEmptyString),
|
|
1105
|
+
// `1` from a gateway that runs a workspace's SSH sessions as its `sshUser`. A workspace with a
|
|
1106
|
+
// user answers no target to a gateway without it, which would run the session as root.
|
|
1107
|
+
"x-sealant-gateway-ssh-user": Schema.optional(NonEmptyString),
|
|
1075
1108
|
});
|
|
1076
1109
|
export class WorkspaceBadRequestError extends Schema.TaggedErrorClass()("WorkspaceBadRequestError", {
|
|
1077
1110
|
message: Schema.String,
|
|
@@ -1105,6 +1138,16 @@ export class WorkspaceUnauthorizedError extends Schema.TaggedErrorClass()("Works
|
|
|
1105
1138
|
message: Schema.String,
|
|
1106
1139
|
}, { httpApiStatus: 401 }) {
|
|
1107
1140
|
}
|
|
1141
|
+
/**
|
|
1142
|
+
* `sshAsOwner` refused: the owner is bound to no person (`ssh-owner-unbound`), the create carries no
|
|
1143
|
+
* capture owner map (`ssh-owner-needs-owner-map`), or the owner map or `credentialsHome` does not
|
|
1144
|
+
* give the owner's bound person their own uid and home (`ssh-owner-mismatch`). Names no path.
|
|
1145
|
+
*/
|
|
1146
|
+
export class WorkspaceSshOwnerRefusedError extends Schema.TaggedErrorClass()("WorkspaceSshOwnerRefusedError", {
|
|
1147
|
+
message: Schema.String,
|
|
1148
|
+
code: Schema.Literals(["ssh-owner-unbound", "ssh-owner-needs-owner-map", "ssh-owner-mismatch"]),
|
|
1149
|
+
}, { httpApiStatus: 403 }) {
|
|
1150
|
+
}
|
|
1108
1151
|
export class WorkspaceForbiddenError extends Schema.TaggedErrorClass()("WorkspaceForbiddenError", {
|
|
1109
1152
|
message: Schema.String,
|
|
1110
1153
|
}, { httpApiStatus: 403 }) {
|
|
@@ -1150,6 +1193,7 @@ export const WorkspacesGroup = HttpApiGroup.make("workspaces")
|
|
|
1150
1193
|
WorkspaceRuntimeEnvReferencesUnsupportedError,
|
|
1151
1194
|
WorkspaceDockerServiceUnsupportedError,
|
|
1152
1195
|
WorkspaceForbiddenError,
|
|
1196
|
+
WorkspaceSshOwnerRefusedError,
|
|
1153
1197
|
WorkspaceNotFoundError,
|
|
1154
1198
|
// Selected connected account exists but is not usable (status "invalid").
|
|
1155
1199
|
WorkspaceConflictError,
|
|
@@ -1414,6 +1458,12 @@ HttpApiEndpoint.post("expireWorkspace", "/:workspaceId/expire", {
|
|
|
1414
1458
|
payload: renameWorkspaceRequestSchema,
|
|
1415
1459
|
success: renameWorkspaceResponseSchema,
|
|
1416
1460
|
error: [WorkspaceNotFoundError, WorkspaceInternalServerError],
|
|
1461
|
+
}))
|
|
1462
|
+
.add(HttpApiEndpoint.delete("clearWorkspaceSshUser", "/:workspaceId/ssh-user", {
|
|
1463
|
+
params: workspaceIdParams,
|
|
1464
|
+
query: clearWorkspaceSshUserQuerySchema,
|
|
1465
|
+
success: clearWorkspaceSshUserResponseSchema,
|
|
1466
|
+
error: [WorkspaceNotFoundError, WorkspaceInternalServerError],
|
|
1417
1467
|
}))
|
|
1418
1468
|
.add(HttpApiEndpoint.get("listWorkspaces", "/", {
|
|
1419
1469
|
query: listWorkspacesQuerySchema,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sealant/api-contracts-next",
|
|
3
|
-
"version": "0.39.0-next.
|
|
3
|
+
"version": "0.39.0-next.714",
|
|
4
4
|
"description": "Contract-first HTTP API definitions for Sealant services",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"effect": ">=4.0.0-beta.85 <5"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "6da21a94e3f8650df5cbdb53626f420981cd1831",
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
38
38
|
}
|