feat(libgsh): Phase 0 — typed Did on AcPrincipal
`AcPrincipal.did: Option<String>` → `Option<guildhouse_did::Did>`. The AuthorizationContext now carries a W3C-canonical typed DID; malformed DIDs fail at deserialize time rather than propagating into the corpus_check / session state. SessionState.principal stays a String — it can also hold a Unix username in ungoverned mode, so a typed Did would force Option<Did> there and complicate the chain. The render at SessionState::from_ac now goes Did → as_str() instead of cloning the legacy String. Behaviour at the audit-leaf level is unchanged when the AC carries a valid `did:web:...` payload. Phase 0 of DESIGN-DID-INTEGRATION-2026-04-29 §5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Tyler J King <tking@guildhouse.dev>
This commit is contained in:
parent
91f027ae61
commit
f810537581
7 changed files with 276 additions and 15 deletions
228
Cargo.lock
generated
228
Cargo.lock
generated
|
|
@ -67,6 +67,17 @@ version = "1.0.102"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.89"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic-waker"
|
name = "atomic-waker"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
|
|
@ -90,12 +101,34 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base-x"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base256emoji"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c"
|
||||||
|
dependencies = [
|
||||||
|
"const-str",
|
||||||
|
"match-lookup",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64ct"
|
||||||
|
version = "1.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.11.0"
|
version = "2.11.0"
|
||||||
|
|
@ -212,6 +245,18 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-oid"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-str"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
@ -283,6 +328,69 @@ dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek"
|
||||||
|
version = "4.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"curve25519-dalek-derive",
|
||||||
|
"digest",
|
||||||
|
"fiat-crypto",
|
||||||
|
"rustc_version",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "curve25519-dalek-derive"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "data-encoding"
|
||||||
|
version = "2.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "data-encoding-macro"
|
||||||
|
version = "0.1.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3259c913752a86488b501ed8680446a5ed2d5aeac6e596cb23ba3800768ea32c"
|
||||||
|
dependencies = [
|
||||||
|
"data-encoding",
|
||||||
|
"data-encoding-macro-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "data-encoding-macro-internal"
|
||||||
|
version = "0.1.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
|
||||||
|
dependencies = [
|
||||||
|
"data-encoding",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "der"
|
||||||
|
version = "0.7.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||||
|
dependencies = [
|
||||||
|
"const-oid",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
|
|
@ -325,6 +433,32 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519"
|
||||||
|
version = "2.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
|
||||||
|
dependencies = [
|
||||||
|
"pkcs8",
|
||||||
|
"serde",
|
||||||
|
"signature",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ed25519-dalek"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
|
||||||
|
dependencies = [
|
||||||
|
"curve25519-dalek",
|
||||||
|
"ed25519",
|
||||||
|
"rand_core",
|
||||||
|
"serde",
|
||||||
|
"sha2",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
|
|
@ -373,6 +507,12 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fiat-crypto"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
|
@ -514,6 +654,23 @@ dependencies = [
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "guildhouse-did"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"chrono",
|
||||||
|
"ed25519-dalek",
|
||||||
|
"hex",
|
||||||
|
"multibase",
|
||||||
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
|
|
@ -904,6 +1061,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
"guildhouse-did",
|
||||||
"hex",
|
"hex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -956,6 +1114,17 @@ version = "0.4.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "match-lookup"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.8.0"
|
version = "2.8.0"
|
||||||
|
|
@ -980,6 +1149,18 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multibase"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8694bb4835f452b0e3bb06dbebb1d6fc5385b6ca1caf2e55fd165c042390ec77"
|
||||||
|
dependencies = [
|
||||||
|
"base-x",
|
||||||
|
"base256emoji",
|
||||||
|
"data-encoding",
|
||||||
|
"data-encoding-macro",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.18"
|
version = "0.2.18"
|
||||||
|
|
@ -1112,6 +1293,16 @@ version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkcs8"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
|
|
@ -1161,6 +1352,15 @@ version = "6.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.17",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.18"
|
version = "0.5.18"
|
||||||
|
|
@ -1257,6 +1457,15 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.44"
|
version = "0.38.44"
|
||||||
|
|
@ -1475,6 +1684,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signature"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
|
|
@ -1497,6 +1715,16 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spki"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
|
||||||
|
dependencies = [
|
||||||
|
"base64ct",
|
||||||
|
"der",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
# gsh
|
# gsh
|
||||||
|
|
||||||
gsh — the GCAP governed shell. Human and machine modes. Chronicle-attributed execution.
|
gsh — the GCAP governed shell. Human and machine modes. Chronicle-attributed execution.
|
||||||
|
|
||||||
|
**Status (2026-04-28):** Active development. Design is mature ([DESIGN.md](DESIGN.md)). The architectural anchor is the shell type system (per [DESIGN-SHELL-ARCHITECTURE-2026-04-28.md](../DESIGN-SHELL-ARCHITECTURE-2026-04-28.md)); gsh is the canonical consumer of the type system, built on libgsh.
|
||||||
|
|
@ -5,6 +5,7 @@ edition.workspace = true
|
||||||
description = "Governed shell library — AC validation, CR building, corpus gate"
|
description = "Governed shell library — AC validation, CR building, corpus gate"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
guildhouse-did = { path = "../../guildhouse-did" }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
//! Authorization Context validation (R-22, R-23, R-24).
|
//! Authorization Context validation (R-22, R-23, R-24).
|
||||||
|
|
||||||
|
use guildhouse_did::Did;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
@ -32,7 +33,7 @@ pub struct AcOperation {
|
||||||
#[derive(Deserialize, Debug, Clone, Default)]
|
#[derive(Deserialize, Debug, Clone, Default)]
|
||||||
pub struct AcPrincipal {
|
pub struct AcPrincipal {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub did: Option<String>,
|
pub did: Option<Did>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub display_name: Option<String>,
|
pub display_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,15 @@
|
||||||
//! Configuration from environment variables.
|
//! Configuration from environment variables.
|
||||||
|
|
||||||
|
use guildhouse_did::Did;
|
||||||
|
|
||||||
/// Consolidated gsh configuration from env vars.
|
/// Consolidated gsh configuration from env vars.
|
||||||
pub struct GshConfig {
|
pub struct GshConfig {
|
||||||
/// Pre-issued AC JSON string.
|
/// Pre-issued AC JSON string.
|
||||||
pub ac: Option<String>,
|
pub ac: Option<String>,
|
||||||
/// GSAP broker URL.
|
/// GSAP broker URL.
|
||||||
pub broker_url: Option<String>,
|
pub broker_url: Option<String>,
|
||||||
/// Agent DID.
|
/// Agent DID. None when `GSAP_AGENT_DID` is unset or doesn't parse as a DID.
|
||||||
pub agent_did: Option<String>,
|
pub agent_did: Option<Did>,
|
||||||
/// Bearer auth token.
|
/// Bearer auth token.
|
||||||
pub token: Option<String>,
|
pub token: Option<String>,
|
||||||
/// Corpus CID this session is authorized for.
|
/// Corpus CID this session is authorized for.
|
||||||
|
|
@ -28,7 +30,9 @@ impl GshConfig {
|
||||||
Self {
|
Self {
|
||||||
ac: std::env::var("GSAP_AC").ok(),
|
ac: std::env::var("GSAP_AC").ok(),
|
||||||
broker_url: std::env::var("GSAP_BROKER_URL").ok(),
|
broker_url: std::env::var("GSAP_BROKER_URL").ok(),
|
||||||
agent_did: std::env::var("GSAP_AGENT_DID").ok(),
|
agent_did: std::env::var("GSAP_AGENT_DID")
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| Did::parse(&s).ok()),
|
||||||
token: std::env::var("GSAP_TOKEN").ok(),
|
token: std::env::var("GSAP_TOKEN").ok(),
|
||||||
corpus_cid: std::env::var("GSAP_CORPUS_CID")
|
corpus_cid: std::env::var("GSAP_CORPUS_CID")
|
||||||
.unwrap_or_else(|_| "sha256:ungoverned".into()),
|
.unwrap_or_else(|_| "sha256:ungoverned".into()),
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,13 @@ pub fn broker_url(base: &str, path: &str) -> String {
|
||||||
pub fn post_cr(client: &Client, base: &str, ac_id: &str, outcome: &str) -> CrResult {
|
pub fn post_cr(client: &Client, base: &str, ac_id: &str, outcome: &str) -> CrResult {
|
||||||
let now = chrono::Utc::now().to_rfc3339();
|
let now = chrono::Utc::now().to_rfc3339();
|
||||||
let session_id = std::env::var("CHRONICLE_SESSION_ID").unwrap_or_default();
|
let session_id = std::env::var("CHRONICLE_SESSION_ID").unwrap_or_default();
|
||||||
|
// Phase 0 D1: FFC DID sourced from env (FFC_DID), not hardcoded.
|
||||||
|
// W3C colon form. Empty on error → null in payload.
|
||||||
|
let ffc_did = std::env::var("FFC_DID")
|
||||||
|
.ok()
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.and_then(|s| guildhouse_did::Did::parse(&s).ok())
|
||||||
|
.map(|d| d.as_str().to_owned());
|
||||||
|
|
||||||
match client
|
match client
|
||||||
.post(broker_url(base, "governance/complete/"))
|
.post(broker_url(base, "governance/complete/"))
|
||||||
|
|
@ -85,7 +92,7 @@ pub fn post_cr(client: &Client, base: &str, ac_id: &str, outcome: &str) -> CrRes
|
||||||
behavioral_attestation: CrAttestation {
|
behavioral_attestation: CrAttestation {
|
||||||
status: "unavailable".into(),
|
status: "unavailable".into(),
|
||||||
},
|
},
|
||||||
ffc: serde_json::json!({"did": "did:web:guildhouse.dev", "chronicle_session_id": session_id}),
|
ffc: serde_json::json!({"did": ffc_did, "chronicle_session_id": session_id}),
|
||||||
signature: serde_json::json!({"value": "gsh"}),
|
signature: serde_json::json!({"value": "gsh"}),
|
||||||
})
|
})
|
||||||
.send()
|
.send()
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,14 @@ pub struct SessionState {
|
||||||
|
|
||||||
impl SessionState {
|
impl SessionState {
|
||||||
pub fn from_ac(ac: &AuthorizationContext, corpus_cid: &str) -> Self {
|
pub fn from_ac(ac: &AuthorizationContext, corpus_cid: &str) -> Self {
|
||||||
|
// Phase 0: AcPrincipal.did is now Did-typed. Render to canonical
|
||||||
|
// string for SessionState.principal (which stays String — it can
|
||||||
|
// also hold a Unix username in ungoverned mode, so a typed Did
|
||||||
|
// would force Option<Did> here and complicate the chain).
|
||||||
let principal = ac
|
let principal = ac
|
||||||
.principal
|
.principal
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|p| p.did.clone())
|
.and_then(|p| p.did.as_ref().map(|d| d.as_str().to_owned()))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
ac.principal
|
ac.principal
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
@ -114,16 +118,30 @@ fn whoami() -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derive a human-readable display name from a DID.
|
/// Derive a human-readable display name from a DID.
|
||||||
/// did:web:guildhouse.dev/user/tking → tking@guildhouse.dev
|
///
|
||||||
/// Fallback: return the full DID.
|
/// Phase 0 D1: prefers the W3C-canonical colon form
|
||||||
|
/// (`did:web:host:user:tking → tking@host`). The legacy slash form
|
||||||
|
/// (`did:web:host/user/tking`) is also recognized as a transition
|
||||||
|
/// affordance so any stale stored DIDs render sensibly. Falls through
|
||||||
|
/// to the input string when no `did:web:` prefix is present.
|
||||||
fn display_name_from_did(did: &str) -> String {
|
fn display_name_from_did(did: &str) -> String {
|
||||||
if let Some(rest) = did.strip_prefix("did:web:") {
|
let Some(rest) = did.strip_prefix("did:web:") else {
|
||||||
let parts: Vec<&str> = rest.splitn(2, '/').collect();
|
return did.to_string();
|
||||||
if parts.len() == 2 {
|
};
|
||||||
let domain = parts[0];
|
|
||||||
let name = parts[1].rsplit('/').next().unwrap_or(parts[1]);
|
// Try colon form first: `host:seg1:...:segN` → name=segN, domain=host.
|
||||||
return format!("{}@{}", name, domain);
|
if let Some((domain, path)) = rest.split_once(':') {
|
||||||
|
if !path.is_empty() {
|
||||||
|
let name = path.rsplit(':').next().unwrap_or(path);
|
||||||
|
return format!("{name}@{domain}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Legacy slash form: `host/user/tking`.
|
||||||
|
if let Some((domain, path)) = rest.split_once('/') {
|
||||||
|
let name = path.rsplit('/').next().unwrap_or(path);
|
||||||
|
return format!("{name}@{domain}");
|
||||||
|
}
|
||||||
|
|
||||||
did.to_string()
|
did.to_string()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue