Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dag/extdeps/filesystem/filesystem_io.dag
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ service Filesystem {
entries: String from "entries"
success: Bool from "list_success"
error: String from "error"
error_kind: String from "error_kind"
}
readonly
transport file { path: "{path}", verb: "list" }
Expand Down
39 changes: 0 additions & 39 deletions dag/extdeps/google/issue_tracker.dag
Original file line number Diff line number Diff line change
Expand Up @@ -545,45 +545,6 @@ type IssueActionBar {
actions: List<IssueActionKind>
}

// THE FLEET COMPONENT TREE (owner directive 2026-09-24: srvN as the component/asset hierarchy so
// fleet issues carry a real component placement). SOURCES, stated honestly: the host roster and
// the group placement are the fleet's own modeled facts — srv1..srv4 the runner fleet, srv5..srv12
// the Sparks, and the serving arms per the fabric observation's cages (cage 1 = group A on
// srv5..srv8, cage 2 = group B on srv9..srv12; gunbc.spark.fabric_switch_observed
// fabric_group_hosts) — carried here as OWNER-DIRECTED interface rows citing the fleet modules,
// not re-derived at read time. Component ids are stable table keys, not derived from the path.
data fleet_component_hosts: List<Component> = [
Component { id: 1, path: ["srv1"] },
Component { id: 2, path: ["srv2"] },
Component { id: 3, path: ["srv3"] },
Component { id: 4, path: ["srv4"] },
Component { id: 5, path: ["srv5"] },
Component { id: 6, path: ["srv6"] },
Component { id: 7, path: ["srv7"] },
Component { id: 8, path: ["srv8"] },
Component { id: 9, path: ["srv9"] },
Component { id: 10, path: ["srv10"] },
Component { id: 11, path: ["srv11"] },
Component { id: 12, path: ["srv12"] },
]

// THE SERVING-ARM SUB-COMPONENTS: each Spark host carries its serving arm as a sub-component
// (path = host path + the arm), so an issue's component placement names the arm it touches.
data fleet_component_serving_arms: List<Component> = [
Component { id: 105, path: ["srv5", "serving", "group-a"] },
Component { id: 106, path: ["srv6", "serving", "group-a"] },
Component { id: 107, path: ["srv7", "serving", "group-a"] },
Component { id: 108, path: ["srv8", "serving", "group-a"] },
Component { id: 109, path: ["srv9", "serving", "group-b"] },
Component { id: 110, path: ["srv10", "serving", "group-b"] },
Component { id: 111, path: ["srv11", "serving", "group-b"] },
Component { id: 112, path: ["srv12", "serving", "group-b"] },
]

fn fleet_components() -> List<Component> {
concat(fleet_component_hosts, fleet_component_serving_arms)
}

// A COMPONENT'S PLACEMENT IS ITS PATH (the type's own law): the browse tree derives from the
// paths, never a second spelling. "Browse components" is one of the four navigation/curation
// sidebar surfaces (stock_sidebar_roster) — the tree it renders is THIS derivation over the
Expand Down
95 changes: 94 additions & 1 deletion dag/extdeps/google/workspace.dag
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module extdeps.google.workspace

import std.types { NonEmptyStr }
import std.types { NonEmptyStr, String, Bool, List }
import std.decl_ref { DeclarationRef, WholeDeclaration }
import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef }
import extdeps.uri { Uri, Https }
Expand Down Expand Up @@ -32,3 +32,96 @@ data extdeps_model_scope: ExternalModelScope = ExternalModelScope {
first_citation: extdeps_external_authority_anchor,
further_citations: [google_workspace_credentials_citation]
}

// Reviewed 2026-09-28 against Google's Auth Platform, Admin console and Policy API documentation.
// API availability is per setting and operation. A directory/user/photo API is not an API for
// its governing policy. IAM oauthClients is Workforce Identity Federation, not Auth Platform.

type WorkspaceAdminControl
= OAuthClientRegistration
| OAuthApplicationAudience
| OAuthClientAppAccess
| ExternalDirectorySharing
| ProfilePhotoEditing

type WorkspaceAdminSubject
= AuthPlatformClient { project: NonEmptyStr, client: NonEmptyStr }
| AuthPlatformAudience { project: NonEmptyStr }
| WorkspaceClientAccess { customer: NonEmptyStr, client: NonEmptyStr, org_unit: NonEmptyStr }
| WorkspaceDirectorySharing { customer: NonEmptyStr }
| WorkspacePhotoEditing { customer: NonEmptyStr, org_unit: NonEmptyStr }

type WorkspaceAppAccess = AppTrusted | AppLimited | AppBlocked | AppSpecificGoogleData { scopes: List<NonEmptyStr> }
type WorkspaceDirectorySharingPolicy = RequesterBasicProfileOnly | OrganizationDirectoryData

type WorkspaceAdminValue
= RegisteredWebClient { redirect_uris: List<NonEmptyStr> }
| InternalAudience
| ExternalAudience
| ClientAccess { access: WorkspaceAppAccess }
| DirectorySharing { policy: WorkspaceDirectorySharingPolicy }
| PhotoEditing { allowed: Bool }

type WorkspaceAdminReadSurface
= ConsoleReadbackRequired { documentation: NonEmptyStr }
| PolicyApiReadSupported { setting_type: NonEmptyStr, documentation: NonEmptyStr }

type WorkspaceAdminWriteSurface = ManualConsoleAdministration { documentation: NonEmptyStr }

data workspace_policy_settings_documentation: NonEmptyStr = "https://docs.cloud.google.com/identity/docs/concepts/supported-policy-api-settings"
data workspace_policy_read_documentation: NonEmptyStr = "https://docs.cloud.google.com/identity/docs/how-to/list-get-policies"
data workspace_policy_readonly_scope: NonEmptyStr = "https://www.googleapis.com/auth/cloud-identity.policies.readonly"
data workspace_policy_list_endpoint: NonEmptyStr = "https://cloudidentity.googleapis.com/v1/policies"
data workspace_policy_reduction_documentation: NonEmptyStr = "https://docs.cloud.google.com/identity/docs/concepts/policy-api-concepts"

fn workspace_admin_control(subject: WorkspaceAdminSubject) -> WorkspaceAdminControl {
match subject {
AuthPlatformClient { project: _, client: _ } => OAuthClientRegistration
AuthPlatformAudience { project: _ } => OAuthApplicationAudience
WorkspaceClientAccess { customer: _, client: _, org_unit: _ } => OAuthClientAppAccess
WorkspaceDirectorySharing { customer: _ } => ExternalDirectorySharing
WorkspacePhotoEditing { customer: _, org_unit: _ } => ProfilePhotoEditing
}
}

fn workspace_admin_value_control(value: WorkspaceAdminValue) -> WorkspaceAdminControl {
match value {
RegisteredWebClient { redirect_uris: _ } => OAuthClientRegistration
InternalAudience => OAuthApplicationAudience
ExternalAudience => OAuthApplicationAudience
ClientAccess { access: _ } => OAuthClientAppAccess
DirectorySharing { policy: _ } => ExternalDirectorySharing
PhotoEditing { allowed: _ } => ProfilePhotoEditing
}
}

fn workspace_admin_console_documentation(control: WorkspaceAdminControl) -> NonEmptyStr {
match control {
OAuthClientRegistration => "https://support.google.com/cloud/answer/15549257"
OAuthApplicationAudience => "https://developers.google.com/workspace/guides/configure-oauth-consent"
OAuthClientAppAccess => "https://support.google.com/a/answer/7281227"
ExternalDirectorySharing => "https://knowledge.workspace.google.com/admin/users/let-third-party-apps-access-directory-data"
ProfilePhotoEditing => "https://knowledge.workspace.google.com/admin/users/allow-directory-users-to-change-their-profile-and-photo"
}
}

// No documented supported read for rows 1, 2, 3 or 5 in the reviewed interface inventories.
// This is a dated interface qualification, not a claim that Google can never expose one.
fn workspace_admin_read_surface(control: WorkspaceAdminControl) -> WorkspaceAdminReadSurface {
match control {
ExternalDirectorySharing => PolicyApiReadSupported { setting_type: "directory.external_directory_sharing", documentation: workspace_policy_settings_documentation }
_ => ConsoleReadbackRequired { documentation: workspace_admin_console_documentation(control: control) }
}
}

fn workspace_admin_write_surface(control: WorkspaceAdminControl) -> WorkspaceAdminWriteSurface {
ManualConsoleAdministration { documentation: workspace_admin_console_documentation(control: control) }
}

// The literal policy enum is distinct from absence/refusal; an omitted/default setting needs
// the provider's policy reduction/default rules, never an assumption based on a successful login.
fn workspace_directory_sharing_value(wire: String) -> WorkspaceDirectorySharingPolicy? {
if wire == "REQUESTER_BASIC_PROFILE_ONLY" { Present { value: RequesterBasicProfileOnly } }
else if wire == "ORGANIZATION_DIRECTORY_DATA" { Present { value: OrganizationDirectoryData } }
else { none }
}
81 changes: 81 additions & 0 deletions dag/extdeps/http/form_urlencoded.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
module extdeps.http.form_urlencoded

import std.types { String, List, Bool, Int }
import std.integer { UInt8 }
import std.bytes { utf8_encode_bytes, bytes_octets }
import std.encoding { utf8_decode_octets }

// WHATWG URL, application/x-www-form-urlencoded: split pairs before decoding, plus means space,
// percent escapes decode exactly once. This admission refuses malformed escapes/UTF-8 and duplicate
// fields rather than selecting an ambiguous command. https://url.spec.whatwg.org/#urlencoded-parsing
// Empty and absent fields remain distinct. CRLF and field-looking lines inside values are data.
type FormField { name: String, value: String }
type FormRead = FormDecoded { fields: List<FormField> } | FormRefused { reason: String }
type FormOctets = FormOctetsDecoded { octets: List<UInt8> } | FormOctetsRefused

fn form_hex(o: UInt8) -> Int? {
if o >= 48 && o <= 57 { Present { value: (o as Int) - 48 } }
else if o >= 65 && o <= 70 { Present { value: (o as Int) - 55 } }
else if o >= 97 && o <= 102 { Present { value: (o as Int) - 87 } }
else { none }
}

fn form_unescape(octets: List<UInt8>, acc: List<UInt8>) -> FormOctets {
match octets.first() {
Absent => FormOctetsDecoded { octets: acc }
Present { value: head } => if head == 43 { form_unescape(octets: octets.skip(n: 1), acc: concat(acc, [32])) }
else if head != 37 { form_unescape(octets: octets.skip(n: 1), acc: concat(acc, [head])) }
else { match octets.skip(n: 1).first() {
Absent => FormOctetsRefused
Present { value: h } => match octets.skip(n: 2).first() {
Absent => FormOctetsRefused
Present { value: l } => match form_hex(o: h) {
Absent => FormOctetsRefused
Present { value: high } => match form_hex(o: l) {
Absent => FormOctetsRefused
Present { value: low } => form_unescape(octets: octets.skip(n: 3), acc: concat(acc, [high * 16 + low]))
}
}
}
} }
}
}

fn form_component(wire: String) -> String? {
match form_unescape(octets: bytes_octets(b: utf8_encode_bytes(s: wire)), acc: []) {
FormOctetsRefused => none
FormOctetsDecoded { octets } => match utf8_decode_octets(octets: octets) {
Absent => none
Present { value: scalars } => Present { value: join(map(scalars, cp => from_code_point(cp: cp)), "") }
}
}
}

fn form_decode(wire: String) -> FormRead {
fold(filter(split(s: wire, delimiter: "&"), part => part != ""), init: FormDecoded { fields: [] }, f: (state, part) => match state {
FormRefused { reason } => FormRefused { reason: reason }
FormDecoded { fields } => {
let pieces = split(s: part, delimiter: "=")
let name_wire = match pieces.first() { Present { value: first } => first Absent => "" }
let value_wire = join(pieces.skip(n: 1), "=")
match form_component(wire: name_wire) {
Absent => FormRefused { reason: "invalid encoded form name" }
Present { value: name } => if any(fields, field => field.name == name) { FormRefused { reason: "duplicate form field" } }
else { match form_component(wire: value_wire) {
Absent => FormRefused { reason: "invalid encoded form value" }
Present { value } => FormDecoded { fields: concat(fields, [FormField { name: name, value: value }]) }
} }
}
}
})
}

fn form_field(form: FormRead, name: String) -> String? {
match form {
FormRefused { reason: _ } => none
FormDecoded { fields } => match filter(fields, field => field.name == name).first() {
Absent => none
Present { value: field } => Present { value: field.value }
}
}
}
Loading