fix: type runtime config and test passkey lifecycle
This commit is contained in:
Generated
+78
@@ -255,6 +255,28 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.89"
|
||||
@@ -4014,6 +4036,16 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_cbor_2"
|
||||
version = "0.13.0"
|
||||
@@ -4847,6 +4879,18 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.28.0"
|
||||
@@ -5571,6 +5615,39 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webauthn-authenticator-rs"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "779e9c80ff248c7e12ea967f909249101f6e86f70fccd742d4b66c490c1710b4"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"base64 0.21.7",
|
||||
"base64urlsafedata",
|
||||
"bitflags 1.3.2",
|
||||
"futures",
|
||||
"hex",
|
||||
"nom 7.1.3",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"openssl",
|
||||
"openssl-sys",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"serde_cbor_2",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"unicode-normalization",
|
||||
"url",
|
||||
"uuid",
|
||||
"webauthn-rs-core",
|
||||
"webauthn-rs-proto",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webauthn-rs"
|
||||
version = "0.5.5"
|
||||
@@ -6338,6 +6415,7 @@ dependencies = [
|
||||
"ts-rs",
|
||||
"url",
|
||||
"uuid",
|
||||
"webauthn-authenticator-rs",
|
||||
"webauthn-rs",
|
||||
"workdir",
|
||||
"worker",
|
||||
|
||||
@@ -3157,10 +3157,171 @@ pub struct WorkspaceRuntimeConfigQuery {
|
||||
pub profile: String,
|
||||
}
|
||||
|
||||
/// Transparent JSON body for the Runtime-owned config bundle wire format.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
|
||||
#[serde(transparent)]
|
||||
pub struct WorkspaceRuntimeConfigResponse(pub serde_json::Value);
|
||||
/// Canonical Runtime config-bundle response projected by Workspace authority.
|
||||
///
|
||||
/// This is intentionally a concrete transport DTO rather than an opaque JSON value so generated
|
||||
/// clients and OpenAPI consumers receive the same complete wire contract as the Runtime.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeConfigResponse {
|
||||
pub metadata: WorkspaceRuntimeConfigMetadata,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub profiles: Vec<WorkspaceRuntimeConfigProfile>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub declarations: Vec<WorkspaceRuntimeConfigDeclaration>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub prompt_catalog: Option<WorkspaceRuntimePromptCatalog>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub profile_source_archive: Option<WorkspaceRuntimeProfileSourceArchive>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub profile_source_archive_handle: Option<WorkspaceRuntimeResourceHandle>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeConfigMetadata {
|
||||
pub id: String,
|
||||
pub digest: String,
|
||||
pub revision: String,
|
||||
pub workspace_id: String,
|
||||
pub created_at: String,
|
||||
pub provenance: WorkspaceRuntimeConfigProvenance,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeConfigProvenance {
|
||||
pub source: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub detail: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeConfigProfile {
|
||||
pub selector: WorkspaceRuntimeProfileSelector,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub label: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(tag = "kind", content = "value", rename_all = "snake_case")]
|
||||
pub enum WorkspaceRuntimeProfileSelector {
|
||||
Builtin(String),
|
||||
Named(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeConfigDeclaration {
|
||||
pub kind: WorkspaceRuntimeConfigDeclarationKind,
|
||||
pub name: String,
|
||||
pub reference: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WorkspaceRuntimeConfigDeclarationKind {
|
||||
SecretRef,
|
||||
MountGrant,
|
||||
NetworkPolicy,
|
||||
ShellPolicy,
|
||||
GitPolicy,
|
||||
CapabilityGrant,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimePromptCatalog {
|
||||
pub templates: BTreeMap<String, String>,
|
||||
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||
pub config_revision: u64,
|
||||
#[serde(default, skip_serializing_if = "String::is_empty")]
|
||||
pub source_digest: String,
|
||||
pub schema_fingerprint: String,
|
||||
pub toolchain_fingerprint: String,
|
||||
pub catalog_digest: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeProfileSourceArchive {
|
||||
pub reference: WorkspaceRuntimeProfileSourceArchiveRef,
|
||||
pub content: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeProfileSourceArchiveRef {
|
||||
pub id: String,
|
||||
pub digest: String,
|
||||
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||
pub size_bytes: u64,
|
||||
pub source_graph: WorkspaceRuntimeProfileSourceGraph,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeProfileSourceGraph {
|
||||
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||
pub source_count: usize,
|
||||
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||
pub total_source_bytes: u64,
|
||||
pub entrypoints: BTreeMap<String, String>,
|
||||
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
|
||||
pub import_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct WorkspaceRuntimeResourceHandle {
|
||||
pub kind: WorkspaceRuntimeResourceKind,
|
||||
pub workspace_id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub scope_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub runtime_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub worker_id: Option<String>,
|
||||
pub resource_id: String,
|
||||
pub digest: String,
|
||||
pub operation: WorkspaceRuntimeResourceOperation,
|
||||
#[schemars(range(min = 0, max = 9_007_199_254_740_991_i64))]
|
||||
pub expires_at_unix_seconds: i64,
|
||||
pub nonce: String,
|
||||
pub revision: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||
pub generation: Option<u64>,
|
||||
#[schemars(range(min = 0, max = 9_007_199_254_740_991_u64))]
|
||||
pub max_bytes: u64,
|
||||
pub content_type: String,
|
||||
pub redaction: WorkspaceRuntimeResourceRedactionPolicy,
|
||||
pub audit_correlation_id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub profile_source_graph: Option<WorkspaceRuntimeProfileSourceGraph>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WorkspaceRuntimeResourceKind {
|
||||
ProfileSourceArchive,
|
||||
RepositorySshAccess,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WorkspaceRuntimeResourceOperation {
|
||||
FetchArchive,
|
||||
FetchOnce,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WorkspaceRuntimeResourceRedactionPolicy {
|
||||
RuntimeInternalOnly,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||
@@ -8962,6 +9123,89 @@ mod skill_typescript_tests {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn runtime_config_response_round_trips_the_complete_config_bundle_shape() {
|
||||
let fixture = serde_json::json!({
|
||||
"metadata": {
|
||||
"id": "bundle-a",
|
||||
"digest": "0123456789abcdef",
|
||||
"revision": "revision-a",
|
||||
"workspace_id": "workspace-a",
|
||||
"created_at": "2026-01-01T00:00:00Z",
|
||||
"provenance": {
|
||||
"source": "workspace_config",
|
||||
"detail": "projected"
|
||||
}
|
||||
},
|
||||
"profiles": [{
|
||||
"selector": { "kind": "builtin", "value": "builtin:companion" },
|
||||
"label": "Companion"
|
||||
}],
|
||||
"declarations": [{
|
||||
"kind": "secret_ref",
|
||||
"name": "github-token",
|
||||
"reference": "secret:github-token"
|
||||
}],
|
||||
"prompt_catalog": {
|
||||
"templates": { "default": "Prompt" },
|
||||
"config_revision": 7,
|
||||
"source_digest": "source-digest",
|
||||
"schema_fingerprint": "schema-a",
|
||||
"toolchain_fingerprint": "toolchain-a",
|
||||
"catalog_digest": "catalog-a"
|
||||
},
|
||||
"profile_source_archive": {
|
||||
"reference": {
|
||||
"id": "archive-a",
|
||||
"digest": "archive-digest",
|
||||
"size_bytes": 3,
|
||||
"source_graph": {
|
||||
"source_count": 1,
|
||||
"total_source_bytes": 3,
|
||||
"entrypoints": { "builtin:companion": "companion.dcdl" },
|
||||
"import_count": 0
|
||||
}
|
||||
},
|
||||
"content": [1, 2, 3]
|
||||
},
|
||||
"profile_source_archive_handle": {
|
||||
"kind": "profile_source_archive",
|
||||
"workspace_id": "workspace-a",
|
||||
"scope_id": "scope-a",
|
||||
"runtime_id": "runtime-a",
|
||||
"worker_id": "worker-a",
|
||||
"resource_id": "resource-a",
|
||||
"digest": "resource-digest",
|
||||
"operation": "fetch_archive",
|
||||
"expires_at_unix_seconds": 1_800_000_000,
|
||||
"nonce": "nonce-a",
|
||||
"revision": "revision-a",
|
||||
"generation": 2,
|
||||
"max_bytes": 1_048_576,
|
||||
"content_type": "application/vnd.yoi.profile-source-archive+tar",
|
||||
"redaction": "runtime_internal_only",
|
||||
"audit_correlation_id": "audit-a",
|
||||
"profile_source_graph": {
|
||||
"source_count": 1,
|
||||
"total_source_bytes": 3,
|
||||
"entrypoints": { "builtin:companion": "companion.dcdl" },
|
||||
"import_count": 0
|
||||
}
|
||||
}
|
||||
});
|
||||
let response: WorkspaceRuntimeConfigResponse =
|
||||
serde_json::from_value(fixture.clone()).unwrap();
|
||||
assert_eq!(serde_json::to_value(response).unwrap(), fixture);
|
||||
|
||||
let mut unknown_nested_field = fixture;
|
||||
unknown_nested_field["metadata"]["runtime_local_path"] =
|
||||
serde_json::Value::String("/private/path".to_string());
|
||||
assert!(
|
||||
serde_json::from_value::<WorkspaceRuntimeConfigResponse>(unknown_nested_field).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn worker_session_contract_and_flattened_availability_are_stable() {
|
||||
let operations = ServerApiMetadata::OPERATIONS;
|
||||
@@ -10896,6 +11140,18 @@ mod openapi_artifact_tests {
|
||||
runtime_config["responses"]["200"]["content"]["application/json"]["schema"]["$ref"],
|
||||
"#/components/schemas/WorkspaceRuntimeConfigResponse"
|
||||
);
|
||||
let runtime_config_schema =
|
||||
&value["components"]["schemas"]["WorkspaceRuntimeConfigResponse"];
|
||||
assert_eq!(runtime_config_schema["type"], "object");
|
||||
assert_eq!(runtime_config_schema["additionalProperties"], false);
|
||||
assert!(runtime_config_schema["properties"]["metadata"].is_object());
|
||||
assert!(runtime_config_schema["properties"]["profiles"].is_object());
|
||||
assert!(runtime_config_schema["properties"]["declarations"].is_object());
|
||||
assert!(
|
||||
value["components"]["schemas"]["WorkspaceRuntimeConfigMetadata"]["properties"]
|
||||
["digest"]
|
||||
.is_object()
|
||||
);
|
||||
assert!(runtime_config["responses"]["304"].get("content").is_none());
|
||||
for status in ["200", "304"] {
|
||||
assert!(runtime_config["responses"][status]["headers"]["etag"].is_object());
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use crate::catalog::{ConfigBundleRef, ProfileSelector};
|
||||
use crate::error::RuntimeError;
|
||||
use crate::profile_archive::{
|
||||
ProfileArchiveError, ProfileSourceArchive, ProfileSourceArchiveRef,
|
||||
ProfileArchiveError, ProfileSourceArchive, ProfileSourceArchiveRef, ProfileSourceGraphSummary,
|
||||
VerifiedProfileSourceArchive,
|
||||
};
|
||||
use crate::resource::{BackendResourceHandle, validate_resource_handle_text};
|
||||
use crate::resource::{
|
||||
BackendResourceHandle, BackendResourceKind, BackendResourceOperation, ResourceRedactionPolicy,
|
||||
validate_resource_handle_text,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
@@ -162,6 +165,181 @@ impl ConfigBundle {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigBundle> for server_api::WorkspaceRuntimeConfigResponse {
|
||||
fn from(bundle: ConfigBundle) -> Self {
|
||||
let ConfigBundle {
|
||||
metadata,
|
||||
profiles,
|
||||
declarations,
|
||||
prompt_catalog,
|
||||
profile_source_archive,
|
||||
profile_source_archive_handle,
|
||||
} = bundle;
|
||||
Self {
|
||||
metadata: metadata.into(),
|
||||
profiles: profiles.into_iter().map(Into::into).collect(),
|
||||
declarations: declarations.into_iter().map(Into::into).collect(),
|
||||
prompt_catalog: prompt_catalog.map(|catalog| {
|
||||
server_api::WorkspaceRuntimePromptCatalog {
|
||||
templates: catalog.templates,
|
||||
config_revision: catalog.config_revision,
|
||||
source_digest: catalog.source_digest,
|
||||
schema_fingerprint: catalog.schema_fingerprint,
|
||||
toolchain_fingerprint: catalog.toolchain_fingerprint,
|
||||
catalog_digest: catalog.catalog_digest,
|
||||
}
|
||||
}),
|
||||
profile_source_archive: profile_source_archive.map(Into::into),
|
||||
profile_source_archive_handle: profile_source_archive_handle.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigBundleMetadata> for server_api::WorkspaceRuntimeConfigMetadata {
|
||||
fn from(metadata: ConfigBundleMetadata) -> Self {
|
||||
Self {
|
||||
id: metadata.id,
|
||||
digest: metadata.digest,
|
||||
revision: metadata.revision,
|
||||
workspace_id: metadata.workspace_id,
|
||||
created_at: metadata.created_at,
|
||||
provenance: metadata.provenance.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigBundleProvenance> for server_api::WorkspaceRuntimeConfigProvenance {
|
||||
fn from(provenance: ConfigBundleProvenance) -> Self {
|
||||
Self {
|
||||
source: provenance.source,
|
||||
detail: provenance.detail,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigProfileDescriptor> for server_api::WorkspaceRuntimeConfigProfile {
|
||||
fn from(profile: ConfigProfileDescriptor) -> Self {
|
||||
Self {
|
||||
selector: profile.selector.into(),
|
||||
label: profile.label,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProfileSelector> for server_api::WorkspaceRuntimeProfileSelector {
|
||||
fn from(selector: ProfileSelector) -> Self {
|
||||
match selector {
|
||||
ProfileSelector::Builtin(value) => Self::Builtin(value),
|
||||
ProfileSelector::Named(value) => Self::Named(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigDeclaration> for server_api::WorkspaceRuntimeConfigDeclaration {
|
||||
fn from(declaration: ConfigDeclaration) -> Self {
|
||||
Self {
|
||||
kind: declaration.kind.into(),
|
||||
name: declaration.name,
|
||||
reference: declaration.reference,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigDeclarationKind> for server_api::WorkspaceRuntimeConfigDeclarationKind {
|
||||
fn from(kind: ConfigDeclarationKind) -> Self {
|
||||
match kind {
|
||||
ConfigDeclarationKind::SecretRef => Self::SecretRef,
|
||||
ConfigDeclarationKind::MountGrant => Self::MountGrant,
|
||||
ConfigDeclarationKind::NetworkPolicy => Self::NetworkPolicy,
|
||||
ConfigDeclarationKind::ShellPolicy => Self::ShellPolicy,
|
||||
ConfigDeclarationKind::GitPolicy => Self::GitPolicy,
|
||||
ConfigDeclarationKind::CapabilityGrant => Self::CapabilityGrant,
|
||||
ConfigDeclarationKind::Unsupported => Self::Unsupported,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProfileSourceArchive> for server_api::WorkspaceRuntimeProfileSourceArchive {
|
||||
fn from(archive: ProfileSourceArchive) -> Self {
|
||||
Self {
|
||||
reference: archive.reference.into(),
|
||||
content: archive.content,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProfileSourceArchiveRef> for server_api::WorkspaceRuntimeProfileSourceArchiveRef {
|
||||
fn from(reference: ProfileSourceArchiveRef) -> Self {
|
||||
Self {
|
||||
id: reference.id,
|
||||
digest: reference.digest,
|
||||
size_bytes: reference.size_bytes,
|
||||
source_graph: reference.source_graph.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProfileSourceGraphSummary> for server_api::WorkspaceRuntimeProfileSourceGraph {
|
||||
fn from(summary: ProfileSourceGraphSummary) -> Self {
|
||||
Self {
|
||||
source_count: summary.source_count,
|
||||
total_source_bytes: summary.total_source_bytes,
|
||||
entrypoints: summary.entrypoints,
|
||||
import_count: summary.import_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BackendResourceHandle> for server_api::WorkspaceRuntimeResourceHandle {
|
||||
fn from(handle: BackendResourceHandle) -> Self {
|
||||
Self {
|
||||
kind: handle.kind.into(),
|
||||
workspace_id: handle.workspace_id,
|
||||
scope_id: handle.scope_id,
|
||||
runtime_id: handle.runtime_id,
|
||||
worker_id: handle.worker_id,
|
||||
resource_id: handle.resource_id,
|
||||
digest: handle.digest,
|
||||
operation: handle.operation.into(),
|
||||
expires_at_unix_seconds: handle.expires_at_unix_seconds,
|
||||
nonce: handle.nonce,
|
||||
revision: handle.revision,
|
||||
generation: handle.generation,
|
||||
max_bytes: handle.max_bytes,
|
||||
content_type: handle.content_type,
|
||||
redaction: handle.redaction.into(),
|
||||
audit_correlation_id: handle.audit_correlation_id,
|
||||
profile_source_graph: handle.profile_source_graph.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BackendResourceKind> for server_api::WorkspaceRuntimeResourceKind {
|
||||
fn from(kind: BackendResourceKind) -> Self {
|
||||
match kind {
|
||||
BackendResourceKind::ProfileSourceArchive => Self::ProfileSourceArchive,
|
||||
BackendResourceKind::RepositorySshAccess => Self::RepositorySshAccess,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BackendResourceOperation> for server_api::WorkspaceRuntimeResourceOperation {
|
||||
fn from(operation: BackendResourceOperation) -> Self {
|
||||
match operation {
|
||||
BackendResourceOperation::FetchArchive => Self::FetchArchive,
|
||||
BackendResourceOperation::FetchOnce => Self::FetchOnce,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ResourceRedactionPolicy> for server_api::WorkspaceRuntimeResourceRedactionPolicy {
|
||||
fn from(policy: ResourceRedactionPolicy) -> Self {
|
||||
match policy {
|
||||
ResourceRedactionPolicy::RuntimeInternalOnly => Self::RuntimeInternalOnly,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ConfigBundleMetadata {
|
||||
pub id: String,
|
||||
|
||||
@@ -53,3 +53,4 @@ webauthn-rs = { workspace = true }
|
||||
tempfile.workspace = true
|
||||
tower = { workspace = true, features = ["util"] }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
||||
webauthn-authenticator-rs = { version = "0.5.5", default-features = false, features = ["softpasskey"] }
|
||||
|
||||
@@ -14855,15 +14855,7 @@ fn workspace_runtime_config_result(
|
||||
},
|
||||
);
|
||||
}
|
||||
let body = serde_json::to_value(bundle)
|
||||
.map(server_api::WorkspaceRuntimeConfigResponse)
|
||||
.map_err(|error| {
|
||||
ApiError::from(invalid_contract_value(
|
||||
"Workspace Runtime Config response",
|
||||
error,
|
||||
))
|
||||
.into_repository_api_error()
|
||||
})?;
|
||||
let body = server_api::WorkspaceRuntimeConfigResponse::from(bundle);
|
||||
Ok(
|
||||
server_api::server_api_responses::WorkspaceRuntimeConfig::Status200 {
|
||||
body,
|
||||
@@ -31612,6 +31604,255 @@ mod tests {
|
||||
assert_ne!(same_origin.status(), StatusCode::FORBIDDEN);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn generated_passkey_routes_complete_registration_login_and_logout_cookie_lifecycle() {
|
||||
use webauthn_authenticator_rs::{WebauthnAuthenticator, softpasskey::SoftPasskey};
|
||||
|
||||
let workspace = tempfile::tempdir().unwrap();
|
||||
let mut api = test_api(workspace.path()).await;
|
||||
let AuthConfig::Passkey {
|
||||
rp_id,
|
||||
origin,
|
||||
public_base_url,
|
||||
cookie_name,
|
||||
} = &mut api.config.auth;
|
||||
*rp_id = "workspace.test".to_string();
|
||||
*origin = "https://workspace.test".to_string();
|
||||
*public_base_url = origin.clone();
|
||||
let origin = origin.clone();
|
||||
let cookie_name = cookie_name.clone();
|
||||
let app = generated_auth_contract_router(ServerApiContractService::Workspace(api));
|
||||
let mut authenticator = WebauthnAuthenticator::new(SoftPasskey::new(true));
|
||||
let authenticator_origin = url::Url::parse(&origin).unwrap();
|
||||
|
||||
let registration_options_response = app
|
||||
.clone()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method(Method::POST)
|
||||
.uri("/api/auth/passkeys/registration/options")
|
||||
.header(ORIGIN, &origin)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(Body::from(
|
||||
serde_json::to_vec(&PasskeyRegistrationOptionsRequest {
|
||||
handle: "generated-passkey-user".to_string(),
|
||||
display_name: Some("Generated Passkey User".to_string()),
|
||||
browser_origin: None,
|
||||
})
|
||||
.unwrap(),
|
||||
))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(registration_options_response.status(), StatusCode::OK);
|
||||
let registration_options: PasskeyRegistrationOptionsResponse = serde_json::from_slice(
|
||||
&to_bytes(registration_options_response.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let registration_credential = authenticator
|
||||
.do_registration(
|
||||
authenticator_origin.clone(),
|
||||
registration_options.public_key,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let registration_response = app
|
||||
.clone()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method(Method::POST)
|
||||
.uri("/api/auth/passkeys/registration/complete")
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(Body::from(
|
||||
serde_json::to_vec(&PasskeyRegistrationCompleteRequest {
|
||||
challenge_id: registration_options.challenge_id,
|
||||
credential: registration_credential,
|
||||
})
|
||||
.unwrap(),
|
||||
))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(registration_response.status(), StatusCode::OK);
|
||||
let registration_cookie = registration_response
|
||||
.headers()
|
||||
.get(axum::http::header::SET_COOKIE)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert!(registration_cookie.starts_with(&format!("{cookie_name}=")));
|
||||
assert!(registration_cookie.contains("; Secure"));
|
||||
assert!(registration_cookie.contains("; HttpOnly; SameSite=Lax"));
|
||||
let registration_body: AuthUserResponse = serde_json::from_slice(
|
||||
&to_bytes(registration_response.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(registration_body.user.handle, "generated-passkey-user");
|
||||
let registration_cookie_pair = registration_cookie.split(';').next().unwrap().to_string();
|
||||
|
||||
let registered_whoami = app
|
||||
.clone()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.uri("/api/auth/whoami")
|
||||
.header(axum::http::header::COOKIE, ®istration_cookie_pair)
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(registered_whoami.status(), StatusCode::OK);
|
||||
let registered_whoami: Value = serde_json::from_slice(
|
||||
&to_bytes(registered_whoami.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
registered_whoami["actor"]["handle"],
|
||||
"generated-passkey-user"
|
||||
);
|
||||
|
||||
let login_options_response = app
|
||||
.clone()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method(Method::POST)
|
||||
.uri("/api/auth/passkeys/login/options")
|
||||
.header(ORIGIN, &origin)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(Body::from(
|
||||
serde_json::to_vec(&PasskeyLoginOptionsRequest {
|
||||
handle: Some("generated-passkey-user".to_string()),
|
||||
browser_origin: None,
|
||||
})
|
||||
.unwrap(),
|
||||
))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(login_options_response.status(), StatusCode::OK);
|
||||
let login_options: PasskeyLoginOptionsResponse = serde_json::from_slice(
|
||||
&to_bytes(login_options_response.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let login_credential = authenticator
|
||||
.do_authentication(authenticator_origin, login_options.public_key)
|
||||
.unwrap();
|
||||
|
||||
let login_response = app
|
||||
.clone()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method(Method::POST)
|
||||
.uri("/api/auth/passkeys/login/complete")
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(Body::from(
|
||||
serde_json::to_vec(&PasskeyLoginCompleteRequest {
|
||||
challenge_id: login_options.challenge_id,
|
||||
credential: login_credential,
|
||||
})
|
||||
.unwrap(),
|
||||
))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(login_response.status(), StatusCode::OK);
|
||||
let login_cookie = login_response
|
||||
.headers()
|
||||
.get(axum::http::header::SET_COOKIE)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
assert!(login_cookie.starts_with(&format!("{cookie_name}=")));
|
||||
assert!(login_cookie.contains("; Secure"));
|
||||
assert!(login_cookie.contains("; HttpOnly; SameSite=Lax"));
|
||||
let login_body: AuthUserResponse = serde_json::from_slice(
|
||||
&to_bytes(login_response.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(login_body.user, registration_body.user);
|
||||
let login_cookie_pair = login_cookie.split(';').next().unwrap().to_string();
|
||||
|
||||
let logged_in_whoami = app
|
||||
.clone()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.uri("/api/auth/whoami")
|
||||
.header(axum::http::header::COOKIE, &login_cookie_pair)
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(logged_in_whoami.status(), StatusCode::OK);
|
||||
let logged_in_whoami: Value = serde_json::from_slice(
|
||||
&to_bytes(logged_in_whoami.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
logged_in_whoami["actor"]["handle"],
|
||||
"generated-passkey-user"
|
||||
);
|
||||
|
||||
let logout_response = app
|
||||
.clone()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method(Method::POST)
|
||||
.uri("/api/auth/logout")
|
||||
.header(axum::http::header::COOKIE, &login_cookie_pair)
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(logout_response.status(), StatusCode::OK);
|
||||
let logout_cookie = logout_response
|
||||
.headers()
|
||||
.get(axum::http::header::SET_COOKIE)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap();
|
||||
assert!(logout_cookie.starts_with(&format!("{cookie_name}=")));
|
||||
assert!(logout_cookie.contains("Max-Age=0"));
|
||||
|
||||
let logged_out_whoami = app
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.uri("/api/auth/whoami")
|
||||
.header(axum::http::header::COOKIE, login_cookie_pair)
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(logged_out_whoami.status(), StatusCode::OK);
|
||||
let logged_out_whoami: Value = serde_json::from_slice(
|
||||
&to_bytes(logged_out_whoami.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(logged_out_whoami["actor"].is_null());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn browser_session_set_and_clear_cookies_follow_public_https_scheme() {
|
||||
for (scheme, secure) in [("http", false), ("https", true)] {
|
||||
@@ -37723,9 +37964,11 @@ mod tests {
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let etag = response.headers().get(ETAG).unwrap().clone();
|
||||
assert_eq!(response.headers().get(CACHE_CONTROL).unwrap(), "no-cache");
|
||||
let body = to_bytes(response.into_body(), usize::MAX).await.unwrap();
|
||||
let contract_bundle: server_api::WorkspaceRuntimeConfigResponse =
|
||||
serde_json::from_slice(&body).unwrap();
|
||||
let bundle: worker_runtime::config_bundle::ConfigBundle =
|
||||
serde_json::from_slice(&to_bytes(response.into_body(), usize::MAX).await.unwrap())
|
||||
.unwrap();
|
||||
serde_json::from_value(serde_json::to_value(contract_bundle).unwrap()).unwrap();
|
||||
assert!(bundle.profile_source_archive.is_some());
|
||||
assert_eq!(
|
||||
etag.to_str().unwrap(),
|
||||
|
||||
+431
-2
@@ -13128,6 +13128,106 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeConfigDeclaration": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"kind": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeConfigDeclarationKind"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"reference": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kind",
|
||||
"name",
|
||||
"reference"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeConfigDeclarationKind": {
|
||||
"enum": [
|
||||
"secret_ref",
|
||||
"mount_grant",
|
||||
"network_policy",
|
||||
"shell_policy",
|
||||
"git_policy",
|
||||
"capability_grant",
|
||||
"unsupported"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WorkspaceRuntimeConfigMetadata": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"provenance": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeConfigProvenance"
|
||||
},
|
||||
"revision": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"digest",
|
||||
"revision",
|
||||
"workspace_id",
|
||||
"created_at",
|
||||
"provenance"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeConfigProfile": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"selector": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeProfileSelector"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"selector"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeConfigProvenance": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"detail": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"source": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"source"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeConfigQuery": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -13141,7 +13241,59 @@
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeConfigResponse": {
|
||||
"description": "Transparent JSON body for the Runtime-owned config bundle wire format."
|
||||
"additionalProperties": false,
|
||||
"description": "Canonical Runtime config-bundle response projected by Workspace authority.\n\nThis is intentionally a concrete transport DTO rather than an opaque JSON value so generated\nclients and OpenAPI consumers receive the same complete wire contract as the Runtime.",
|
||||
"properties": {
|
||||
"declarations": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeConfigDeclaration"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeConfigMetadata"
|
||||
},
|
||||
"profile_source_archive": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeProfileSourceArchive"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profile_source_archive_handle": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeResourceHandle"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"profiles": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeConfigProfile"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"prompt_catalog": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimePromptCatalog"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"metadata"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeDetail": {
|
||||
"additionalProperties": false,
|
||||
@@ -13213,6 +13365,164 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeProfileSelector": {
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"kind": {
|
||||
"const": "builtin",
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kind",
|
||||
"value"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"kind": {
|
||||
"const": "named",
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kind",
|
||||
"value"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"WorkspaceRuntimeProfileSourceArchive": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"content": {
|
||||
"items": {
|
||||
"format": "uint8",
|
||||
"maximum": 255,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"reference": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeProfileSourceArchiveRef"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"reference",
|
||||
"content"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeProfileSourceArchiveRef": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"size_bytes": {
|
||||
"format": "uint64",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"source_graph": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeProfileSourceGraph"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"digest",
|
||||
"size_bytes",
|
||||
"source_graph"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeProfileSourceGraph": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"entrypoints": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"import_count": {
|
||||
"format": "uint",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"source_count": {
|
||||
"format": "uint",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"total_source_bytes": {
|
||||
"format": "uint64",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"source_count",
|
||||
"total_source_bytes",
|
||||
"entrypoints",
|
||||
"import_count"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimePromptCatalog": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"catalog_digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"config_revision": {
|
||||
"format": "uint64",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"schema_fingerprint": {
|
||||
"type": "string"
|
||||
},
|
||||
"source_digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"templates": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"toolchain_fingerprint": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"templates",
|
||||
"config_revision",
|
||||
"schema_fingerprint",
|
||||
"toolchain_fingerprint",
|
||||
"catalog_digest"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeResource": {
|
||||
"properties": {
|
||||
"arch": {
|
||||
@@ -13270,6 +13580,125 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeResourceHandle": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"audit_correlation_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"content_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"expires_at_unix_seconds": {
|
||||
"format": "int64",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"generation": {
|
||||
"format": "uint64",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 0,
|
||||
"type": [
|
||||
"integer",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"kind": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeResourceKind"
|
||||
},
|
||||
"max_bytes": {
|
||||
"format": "uint64",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 0,
|
||||
"type": "integer"
|
||||
},
|
||||
"nonce": {
|
||||
"type": "string"
|
||||
},
|
||||
"operation": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeResourceOperation"
|
||||
},
|
||||
"profile_source_graph": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeProfileSourceGraph"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"redaction": {
|
||||
"$ref": "#/components/schemas/WorkspaceRuntimeResourceRedactionPolicy"
|
||||
},
|
||||
"resource_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"revision": {
|
||||
"type": "string"
|
||||
},
|
||||
"runtime_id": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"scope_id": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"worker_id": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"workspace_id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kind",
|
||||
"workspace_id",
|
||||
"resource_id",
|
||||
"digest",
|
||||
"operation",
|
||||
"expires_at_unix_seconds",
|
||||
"nonce",
|
||||
"revision",
|
||||
"max_bytes",
|
||||
"content_type",
|
||||
"redaction",
|
||||
"audit_correlation_id"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"WorkspaceRuntimeResourceKind": {
|
||||
"enum": [
|
||||
"profile_source_archive",
|
||||
"repository_ssh_access"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WorkspaceRuntimeResourceOperation": {
|
||||
"enum": [
|
||||
"fetch_archive",
|
||||
"fetch_once"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WorkspaceRuntimeResourceRedactionPolicy": {
|
||||
"enum": [
|
||||
"runtime_internal_only"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WorkspaceSigningIdentityPublic": {
|
||||
"additionalProperties": false,
|
||||
"description": "Public metadata for a Workspace signing identity. Private material and its\nstorage reference are deliberately not part of this wire authority.",
|
||||
@@ -13464,7 +13893,7 @@
|
||||
"info": {
|
||||
"title": "Yoi Server API",
|
||||
"version": "0.1.0",
|
||||
"x-yoi-source-digest": "sha256:c76b20e52333efb49a28f9db63d711561bfdc2871e98fd3cbf00d364f2992c21"
|
||||
"x-yoi-source-digest": "sha256:2463eb461342aceb84c87e7aa6bdcf73e28e3866349a555bd4a0d795db671a3f"
|
||||
},
|
||||
"openapi": "3.1.0",
|
||||
"paths": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-companion-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:c76b20e52333efb49a28f9db63d711561bfdc2871e98fd3cbf00d364f2992c21)
|
||||
// Input contract: 0.1.0 (sha256:2463eb461342aceb84c87e7aa6bdcf73e28e3866349a555bd4a0d795db671a3f)
|
||||
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/companion-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:c76b20e52333efb49a28f9db63d711561bfdc2871e98fd3cbf00d364f2992c21)
|
||||
// Input contract: 0.1.0 (sha256:2463eb461342aceb84c87e7aa6bdcf73e28e3866349a555bd4a0d795db671a3f)
|
||||
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/repository-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:c76b20e52333efb49a28f9db63d711561bfdc2871e98fd3cbf00d364f2992c21)
|
||||
// Input contract: 0.1.0 (sha256:2463eb461342aceb84c87e7aa6bdcf73e28e3866349a555bd4a0d795db671a3f)
|
||||
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/runtime-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:c76b20e52333efb49a28f9db63d711561bfdc2871e98fd3cbf00d364f2992c21)
|
||||
// Input contract: 0.1.0 (sha256:2463eb461342aceb84c87e7aa6bdcf73e28e3866349a555bd4a0d795db671a3f)
|
||||
// Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/ticket-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-workdir-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:c76b20e52333efb49a28f9db63d711561bfdc2871e98fd3cbf00d364f2992c21)
|
||||
// Input contract: 0.1.0 (sha256:2463eb461342aceb84c87e7aa6bdcf73e28e3866349a555bd4a0d795db671a3f)
|
||||
// Options: workdir-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/workdir-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_workdir_api_types -- --check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
|
||||
// Input: openapi/server-api.json
|
||||
// Input contract: 0.1.0 (sha256:c76b20e52333efb49a28f9db63d711561bfdc2871e98fd3cbf00d364f2992c21)
|
||||
// Input contract: 0.1.0 (sha256:2463eb461342aceb84c87e7aa6bdcf73e28e3866349a555bd4a0d795db671a3f)
|
||||
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
|
||||
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
|
||||
|
||||
Reference in New Issue
Block a user