Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
e058930
Wall: the approval broker's import closure contains no v2 compiler mo…
Sep 28, 2026
65a42d3
Merge remote-tracking branch 'origin/main' into session/gentle-wren-1…
Sep 29, 2026
1434bfc
Broker closure wall: red control over the narrowest real compiler-rea…
Sep 29, 2026
28d3fe1
CliTool carries its ProgramIdentity; delete the dead resolve/Resolved…
Sep 29, 2026
e3d6f7f
Review 72664: migrate the missed srv3_tool_acquisition reader; refres…
Sep 29, 2026
fd7058b
Floor: cite CliTool in the hermetic-tool-provisioning doc bind; read …
Sep 29, 2026
c8b6c81
Merge remote-tracking branch 'origin/main' into session/gentle-wren-1…
Sep 29, 2026
b8307a6
Keyed module-index reads borrow the cached index instead of cloning i…
Sep 29, 2026
8abb817
Account reference_pool_names as a shared fill
Sep 29, 2026
8c957d2
Enumerate with_module_path_index in the keyed-read seed-growth receipt
Sep 29, 2026
9e21dd8
Host SHA-256 primitive sha256_hex_of_text beside the HMAC seam, with …
Sep 30, 2026
f4d84da
Host SHA-256: known-answer claims on the floor (host == pure transiti…
Sep 30, 2026
b583a71
Place the SHA-256 contract and host fn above the HMAC ones' annotatio…
Sep 30, 2026
90025da
Release-bins lookup: match a tag dispatch's own cache scope in the AP…
Sep 30, 2026
4535828
A service exit arm names a type: v1 parse no longer re-mints it as a …
Sep 30, 2026
5d2e4d0
File nested_field_read_through_a_binder_of_an_inferred_generic_result…
Sep 30, 2026
b65617d
self-host / v2-native-cli: a non-clean emitted build exits 1 WITH its…
Sep 30, 2026
30a5644
WIP: substitution keeps a slot's optional cardinality; VariantNotFoun…
Sep 30, 2026
cfe5aec
Merge remote-tracking branch 'origin/main' into session/neat-pike-685
Sep 30, 2026
402742c
Host SHA-256: citations resolve, frontier stated on the contract, arm…
Sep 30, 2026
9745e2e
Schedule the two new release-bins lookup claims in the wet lane and r…
Sep 30, 2026
f2ba874
WIP: Uniform program installation/access contract (ntfy first)
Sep 30, 2026
d0faa7f
Generic substitution keeps a slot's optional cardinality; VariantNotF…
Sep 30, 2026
fdf1d07
infer_semantics_witness passes the pattern site to the re-signed lookups
Sep 30, 2026
55f6c5a
approve-ios: project the server host from the broker endpoint authori…
Sep 30, 2026
fd2e8ad
approve-ios witness: supply a declared Port row to the refusal claim …
Sep 30, 2026
c25de8f
Broker front door: the backend carries its mount path (tailscale --se…
Sep 30, 2026
3df5fe5
Enrolment handshake: design + model + RED per lost leg (routes, store…
Sep 30, 2026
ace61c2
Front door: mount and backend path derived from one mount-path value …
Sep 30, 2026
37c83b6
Handshake: own EnrolmentActive carrier (VerifiedDeviceEnrollment stay…
Sep 30, 2026
dcb039a
Merge PR #12718 into integration/2026-09-30
Sep 30, 2026
73ac46f
Merge PR #12732 into integration/2026-09-30
Sep 30, 2026
68de932
Merge PR #12712 into integration/2026-09-30
Sep 30, 2026
d70a51b
Merge PR #12523 into integration/2026-09-30
Sep 30, 2026
b09d4b0
Merge PR #12775 into integration/2026-09-30
Sep 30, 2026
41034bc
Merge PR #12784 into integration/2026-09-30
Sep 30, 2026
3c5e4c6
Merge PR #12789 into integration/2026-09-30
Sep 30, 2026
49545cb
Merge PR #12727 into integration/2026-09-30
Sep 30, 2026
833d69e
Merge PR #12748 into integration/2026-09-30
Sep 30, 2026
d36f066
Merge PR #12729 into integration/2026-09-30
Sep 30, 2026
9cb13b1
Merge PR #12738 into integration/2026-09-30
Sep 30, 2026
367c409
Regenerate fleet-converge.yml from the merged authorities (#12727 con…
Sep 30, 2026
18df618
Regenerate stage0 mirrors from the merged src/v1 authorities (#12748,…
Sep 30, 2026
087be8e
Merge remote-tracking branch 'origin/main' into session/wise-bee-807
Sep 30, 2026
45e965e
Revert the #12523 merge: its witness is over the floor budget on its …
Sep 30, 2026
52d05a1
Merge branch 'main' of https://github.com/gunb-ai/gunbc into session/…
Sep 30, 2026
56141ef
Merge origin/main (68ad0673de) into integration/2026-09-30
Sep 30, 2026
ee457bc
Regenerate v1_compiler_infer.rs from the merged src/v1/04_infer.dag (…
Sep 30, 2026
fb5f6e0
Merge origin/main (f63bda4cc7) into integration/2026-09-30
Sep 30, 2026
5e9095e
Regenerate stage0 mirrors from the merged src/v1 authorities (main f6…
Sep 30, 2026
85f3408
Merge branch 'main' of https://github.com/gunb-ai/gunbc into session/…
Sep 30, 2026
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
5 changes: 3 additions & 2 deletions .github/workflows/fleet-converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ jobs:
'jq' '--raw-output' '--exit-status' '. as $answer | [inputs] | if length != 0 then error("the cache-API answer is not exactly one JSON document") else $answer | if type == "object" and (.total_count | type) == "number" and (.actions_caches | type) == "array" and .total_count == (.actions_caches | length) and .total_count <= 100 and all(.actions_caches[]; type == "object" and (.key | type) == "string" and (.ref | type) == "string") then [.actions_caches[] | select(.key == $ENV.RELEASE_BINS_KEY and .ref == "refs/heads/main")] | if length == 0 then "absent" elif length == 1 then "present\nid=\(.[0].id) ref=\(.[0].ref) version=\(.[0].version) created=\(.[0].created_at)" else error("duplicate exact entries") end else error("cache-API answer is not the admitted shape") end end' '.release-bins-lookup-main.json' > "$RUNNER_TEMP"'/lookup-main.decoded' || ('echo' '::error title=release-bins LookupAnswerUnusable::the cache API answer was unreadable or incomplete; it is not treated as absence'; exit 1)
DECODED_STANDING=$('head' '-n' '1' "$RUNNER_TEMP"'/lookup-main.decoded')
if '[' "$DECODED_STANDING" '=' 'present' ']'; then STANDING='present'; ENTRY=$('sed' '-n' '2p' "$RUNNER_TEMP"'/lookup-main.decoded'); else '[' "$DECODED_STANDING" '=' 'absent' ']' || ('echo' '::error title=release-bins LookupAnswerUnusable::the cache API answer was unreadable or incomplete; it is not treated as absence'; exit 1); fi
'curl' '-sSf' '-H' 'Authorization: Bearer '"$GH_TOKEN" '-H' 'Accept: application/vnd.github+json' "$GITHUB_API_URL"'/repos/'"$GITHUB_REPOSITORY"'/actions/caches?per_page=100&key='"$RELEASE_BINS_KEY"'&ref='"$GITHUB_REF" '-o' "$ROOT"'/.release-bins-lookup-dispatch.json' || ('echo' '::error title=release-bins LookupTransportFailed::the cache API lookup FAILED (unreachable or refused); this is not absence, so neither reuse nor rebuild is decided'; exit 1)
'jq' '--raw-output' '--exit-status' '. as $answer | [inputs] | if length != 0 then error("the cache-API answer is not exactly one JSON document") else $answer | if type == "object" and (.total_count | type) == "number" and (.actions_caches | type) == "array" and .total_count == (.actions_caches | length) and .total_count <= 100 and all(.actions_caches[]; type == "object" and (.key | type) == "string" and (.ref | type) == "string") then [.actions_caches[] | select(.key == $ENV.RELEASE_BINS_KEY and .ref == $ENV.GITHUB_REF)] | if length == 0 then "absent" elif length == 1 then "present\nid=\(.[0].id) ref=\(.[0].ref) version=\(.[0].version) created=\(.[0].created_at)" else error("duplicate exact entries") end else error("cache-API answer is not the admitted shape") end end' '.release-bins-lookup-dispatch.json' > "$RUNNER_TEMP"'/lookup-dispatch.decoded' || ('echo' '::error title=release-bins LookupAnswerUnusable::the cache API answer was unreadable or incomplete; it is not treated as absence'; exit 1)
'curl' '-sSf' '-H' 'Authorization: Bearer '"$GH_TOKEN" '-H' 'Accept: application/vnd.github+json' "$GITHUB_API_URL"'/repos/'"$GITHUB_REPOSITORY"'/actions/caches?per_page=100&key='"$RELEASE_BINS_KEY"'&ref='"$RELEASE_BINS_DISPATCH_SCOPE_REF" '-o' "$ROOT"'/.release-bins-lookup-dispatch.json' || ('echo' '::error title=release-bins LookupTransportFailed::the cache API lookup FAILED (unreachable or refused); this is not absence, so neither reuse nor rebuild is decided'; exit 1)
'jq' '--raw-output' '--exit-status' '. as $answer | [inputs] | if length != 0 then error("the cache-API answer is not exactly one JSON document") else $answer | if type == "object" and (.total_count | type) == "number" and (.actions_caches | type) == "array" and .total_count == (.actions_caches | length) and .total_count <= 100 and all(.actions_caches[]; type == "object" and (.key | type) == "string" and (.ref | type) == "string") then [.actions_caches[] | select(.key == $ENV.RELEASE_BINS_KEY and .ref == $ENV.RELEASE_BINS_DISPATCH_SCOPE_REF)] | if length == 0 then "absent" elif length == 1 then "present\nid=\(.[0].id) ref=\(.[0].ref) version=\(.[0].version) created=\(.[0].created_at)" else error("duplicate exact entries") end else error("cache-API answer is not the admitted shape") end end' '.release-bins-lookup-dispatch.json' > "$RUNNER_TEMP"'/lookup-dispatch.decoded' || ('echo' '::error title=release-bins LookupAnswerUnusable::the cache API answer was unreadable or incomplete; it is not treated as absence'; exit 1)
DECODED_STANDING=$('head' '-n' '1' "$RUNNER_TEMP"'/lookup-dispatch.decoded')
if '[' "$DECODED_STANDING" '=' 'present' ']'; then STANDING='present'; ENTRY=$('sed' '-n' '2p' "$RUNNER_TEMP"'/lookup-dispatch.decoded'); else '[' "$DECODED_STANDING" '=' 'absent' ']' || ('echo' '::error title=release-bins LookupAnswerUnusable::the cache API answer was unreadable or incomplete; it is not treated as absence'; exit 1); fi
'echo' 'standing='"$STANDING" | 'tee' '-a' "$GITHUB_OUTPUT" > '/dev/null'
Expand All @@ -229,6 +229,7 @@ jobs:
env:
RELEASE_BINS_KEY: ${{ steps.release_bins_key.outputs.key }}
GH_TOKEN: ${{ github.token }}
RELEASE_BINS_DISPATCH_SCOPE_REF: ${{ startsWith(github.ref, 'refs/tags/') && format('refs/heads/{0}', github.ref) || github.ref }}
timeout-minutes: 5
- name: Restore release-bins into isolated staging (transport only; publishes on a verified build)
id: release_bins_cache
Expand Down
8 changes: 4 additions & 4 deletions apps/approve-ios/Approve/Wire.swift
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,8 @@ enum Route {

// ── Transport ────────────────────────────────────────────────────────────────────────────────
struct ServerConfig {
/// APPROVE_SERVER_HOST from Config/Team.xcconfig via Info.plist. Plain URLSession over the
/// tailnet: no new network path.
/// ApproveServerHost from Info.plist, projected from gunbc.auth.approval_broker_endpoint. Plain
/// URLSession over the tailnet: no new network path.
let host: String
/// apns_environment_wire: "development" | "production".
let apnsEnvironment: String
Expand All @@ -445,14 +445,14 @@ struct ServerConfig {

static func fromBundle() throws -> ServerConfig {
let info = Bundle.main.infoDictionary ?? [:]
guard let host = info["ApproveServerHost"] as? String, !host.isEmpty else { throw WireError.configMissing("APPROVE_SERVER_HOST is empty in Config/Team.xcconfig") }
guard let host = info["ApproveServerHost"] as? String, !host.isEmpty else { throw WireError.configMissing("ApproveServerHost is empty in Info.plist; regenerate the project from project.yml") }
guard let env = info["ApproveApnsEnvironment"] as? String, env == "development" || env == "production" else { throw WireError.configMissing("APNS_ENVIRONMENT must be development or production in Config/Team.xcconfig") }
guard let topic = Bundle.main.bundleIdentifier, !topic.isEmpty else { throw WireError.configMissing("CFBundleIdentifier is missing; the APNs topic cannot be derived") }
// A configured host is a host: refuse anything URLComponents will not carry as one.
var probe = URLComponents()
probe.scheme = "https"
probe.host = host
guard probe.url != nil, probe.host == host, !host.contains("/"), !host.contains("?"), !host.contains("#") else { throw WireError.configMissing("APPROVE_SERVER_HOST is not a bare host: \(host)") }
guard probe.url != nil, probe.host == host, !host.contains("/"), !host.contains("?"), !host.contains("#") else { throw WireError.configMissing("ApproveServerHost is not a bare host: \(host)") }
return ServerConfig(host: host, apnsEnvironment: env, apnsTopic: topic)
}

Expand Down
3 changes: 0 additions & 3 deletions apps/approve-ios/Config/Team.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
// this file by name, so either edit in place (do not commit the team id) or point project.yml at
// the local copy.
DEVELOPMENT_TEAM =
// The roadmap server over the tailnet (gunbc.auth.approval_device_redemption: plain URLSession,
// no new network path). Example: srv1.tailecbe08.ts.net
APPROVE_SERVER_HOST =
// extdeps.apple.apns ApnsEnvironment: development for an Xcode-signed build, production for
// TestFlight and App Store (testflight_is_production_note).
APNS_ENVIRONMENT = development
Expand Down
4 changes: 2 additions & 2 deletions apps/approve-ios/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ held to the `.dag` folds by `dag/test/fixture/approval_device_redemption/vectors
| file | what it is |
|---|---|
| `project.yml` | XcodeGen spec, GENERATED from `gunbc.approve_ios_project` (drift-gated; never hand-edit); no `.xcodeproj` is committed |
| `Config/Team.xcconfig` | operator-filled: `DEVELOPMENT_TEAM`, `APPROVE_SERVER_HOST` (srv1 tailnet host), `APNS_ENVIRONMENT`, `APP_ATTEST_ENVIRONMENT` |
| `Config/Team.xcconfig` | operator-filled: `DEVELOPMENT_TEAM`, `APNS_ENVIRONMENT`, `APP_ATTEST_ENVIRONMENT`. The server host is not here: `project.yml` carries it, projected from `gunbc.auth.approval_broker_endpoint` |
| `Approve/Protocol.swift` | GENERATED (`gunbc.approve_ios_swift_protocol`). `framed` (the injective `<n>:<field>,` rendering), `enrolment_transcript`, `device_redemption_signing_input`, `device_read_client_data`, the protocol records |
| `Approve/Wire.swift` | GENERATED (`gunbc.approve_ios_swift_wire`). Mirror of the modeled HTTP wire: emitter, strict readers, routes, headers; `URLSession` over the tailnet |
| `Approve/DeviceKeys.swift` | enclave decision key (`[.privateKeyUsage, .biometryCurrentSet]` at creation), App Attest, and the one keychain item shape |
Expand All @@ -33,7 +33,7 @@ This repository's containers have no Xcode; nothing here has been compiled. Expe
fixes on first build.

1. `brew install xcodegen`
2. Fill `Config/Team.xcconfig` (team id, `APPROVE_SERVER_HOST`). Keep the team id out of commits.
2. Fill `Config/Team.xcconfig` (team id). Keep the team id out of commits.
3. `cd apps/approve-ios && xcodegen generate && open Approve.xcodeproj`
4. In Signing & Capabilities confirm Push Notifications and App Attest are on the App ID (the
entitlements file declares `aps-environment` and `com.apple.developer.devicecheck.appattest-environment`).
Expand Down
2 changes: 1 addition & 1 deletion apps/approve-ios/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ targets:
CFBundleDisplayName: Approve
UISupportedInterfaceOrientations: [UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown, UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight]
UIBackgroundModes: [remote-notification]
ApproveServerHost: $(APPROVE_SERVER_HOST)
ApproveServerHost: srv1.tailecbe08.ts.net
ApproveApnsEnvironment: $(APNS_ENVIRONMENT)
entitlements:
path: Approve/Approve.entitlements
Expand Down
1 change: 1 addition & 0 deletions dag/extdeps/apple/app_attest.dag
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ fn attestation_verification_from_implementation(
decl_ref(module_path: "extdeps.apple.app_attest", decl_name: "verify_attestation"),
decl_ref(module_path: "test.claim.approval_device_redemption_witness_test", decl_name: "fx_attestation"),
decl_ref(module_path: "test.claim.approval_device_redemption_witness_test", decl_name: "witness_enrolment_refuses_a_refused_attestation"),
decl_ref(module_path: "test.claim.approval_enrolment_handshake_witness_test", decl_name: "fx_attestation"),
]
{
match refusal {
Expand Down
101 changes: 65 additions & 36 deletions dag/gunbc/approve_ios_project.dag
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module gunbc.approve_ios_project

import std.types { String, List }
import std.types { String, List, NonEmptyStr, Port }
import extdeps.apple.property_list { PlistEntry, plist_entry, plist_string }
import extdeps.apple.info_plist {
LaunchScreen, system_default_launch_screen, BackgroundMode, RemoteNotificationMode,
Expand All @@ -14,6 +14,8 @@ import extdeps.apple.build_settings {
MarketingVersion, CurrentProjectVersion
}
import gunbc.auth.approval_app_attest_config { approval_app_bundle_id, approval_app_bundle_version }
import gunbc.auth.approval_broker_endpoint { approval_broker_public_host_from, approval_broker_public_port }
import gunbc.fleet_intent_network { fleet_intent_network }
import extdeps.apple.xcode { xcode_26_6 }
import extdeps.xcodegen.project_spec {
ProjectSpec, ProjectOptions, ConfigFile, XcodeGenTarget, XcodeGenPlist, PlatformDeploymentTarget, DottedVersion,
Expand Down Expand Up @@ -42,7 +44,10 @@ import extdeps.languages.yaml.emit { emit_yaml, EmittedYaml, YamlEmitRefused, ya
// background_modes UIBackgroundModes -- remote-notification, so an approval push wakes the app.
// server_host ApproveServerHost -- read by ServerConfig at launch.
// apns_environment ApproveApnsEnvironment -- read by ServerConfig at launch.
// The last two are xcconfig-substituted from Config/Team.xcconfig.
// apns_environment is xcconfig-substituted from Config/Team.xcconfig. server_host is NOT: it is the
// broker's public host (gunbc.auth.approval_broker_endpoint approval_broker_public_host_from), the
// same composition the approval links are issued against, written into the spec as a value. It was
// an operator-typed APPROVE_SERVER_HOST, a second authority for where the broker answers.
type ApproveAppInfo {
launch_screen: LaunchScreen
face_id_purpose: String
Expand All @@ -53,14 +58,16 @@ type ApproveAppInfo {
apns_environment: String
}

data approve_app_info: ApproveAppInfo = ApproveAppInfo {
launch_screen: system_default_launch_screen,
face_id_purpose: "Approving a request signs it with a key that only unlocks with Face ID.",
display_name: "Approve",
orientations: all_interface_orientations,
background_modes: [RemoteNotificationMode],
server_host: "$(APPROVE_SERVER_HOST)",
apns_environment: "$(APNS_ENVIRONMENT)",
fn approve_app_info(server_host: NonEmptyStr) -> ApproveAppInfo {
ApproveAppInfo {
launch_screen: system_default_launch_screen,
face_id_purpose: "Approving a request signs it with a key that only unlocks with Face ID.",
display_name: "Approve",
orientations: all_interface_orientations,
background_modes: [RemoteNotificationMode],
server_host: server_host as String,
apns_environment: "$(APNS_ENVIRONMENT)",
}
}

fn approve_info_properties(i: ApproveAppInfo) -> List<PlistEntry> {
Expand Down Expand Up @@ -96,8 +103,8 @@ data approve_project_options: ProjectOptions = ProjectOptions {
create_intermediate_groups: true,
}

// DEVELOPMENT_TEAM, APPROVE_SERVER_HOST, APNS_ENVIRONMENT and APP_ATTEST_ENVIRONMENT come from
// Config/Team.xcconfig (operator-local, not generated).
// DEVELOPMENT_TEAM, APNS_ENVIRONMENT and APP_ATTEST_ENVIRONMENT come from Config/Team.xcconfig
// (operator-local, not generated).
// LANGUAGE MODE: Swift 5 (SWIFT_VERSION 5.10) with SWIFT_STRICT_CONCURRENCY complete, i.e. the Swift 6
// mode's data-race checking reported as diagnostics; with warnings as errors (operator ruling,
// 2026-09-24: -D warnings) each of those diagnostics fails the build, which is the Swift 6 bar
Expand All @@ -119,20 +126,22 @@ data approve_project_settings: List<BuildSetting> = [
// the server checks; it is 1 for the bring-up build.
data approve_build_number: String = "1"

data approve_app_target: XcodeGenTarget = XcodeGenTarget {
name: "Approve",
product_type: ApplicationProduct,
platform: IosPlatform,
sources: [SourcePath { path: "Approve" }],
settings: [
BuildSetting { name: ProductBundleIdentifier, value: approval_app_bundle_id },
BuildSetting { name: MarketingVersion, value: approval_app_bundle_version },
BuildSetting { name: CurrentProjectVersion, value: approve_build_number },
BuildSetting { name: AssetCatalogCompilerAppIconName, value: "AppIcon" }
],
info: WritesPlist { plist: XcodeGenPlist { path: "Approve/Info.plist", properties: approve_info_properties(i: approve_app_info) } },
entitlements: WritesPlist { plist: XcodeGenPlist { path: "Approve/Approve.entitlements", properties: approve_entitlements } },
dependencies: [],
fn approve_app_target(server_host: NonEmptyStr) -> XcodeGenTarget {
XcodeGenTarget {
name: "Approve",
product_type: ApplicationProduct,
platform: IosPlatform,
sources: [SourcePath { path: "Approve" }],
settings: [
BuildSetting { name: ProductBundleIdentifier, value: approval_app_bundle_id },
BuildSetting { name: MarketingVersion, value: approval_app_bundle_version },
BuildSetting { name: CurrentProjectVersion, value: approve_build_number },
BuildSetting { name: AssetCatalogCompilerAppIconName, value: "AppIcon" }
],
info: WritesPlist { plist: XcodeGenPlist { path: "Approve/Info.plist", properties: approve_info_properties(i: approve_app_info(server_host: server_host)) } },
entitlements: WritesPlist { plist: XcodeGenPlist { path: "Approve/Approve.entitlements", properties: approve_entitlements } },
dependencies: [],
}
}

// The test bundle carries the fixture vectors EMITTED by gunbc.auth.approval_device_redemption_fixtures
Expand All @@ -150,12 +159,14 @@ data approve_tests_target: XcodeGenTarget = XcodeGenTarget {
dependencies: ["Approve"],
}

data approve_ios_project_spec: ProjectSpec = ProjectSpec {
name: "Approve",
options: approve_project_options,
config_files: [ConfigFile { configuration: "Debug", path: "Config/Team.xcconfig" }, ConfigFile { configuration: "Release", path: "Config/Team.xcconfig" }],
settings: approve_project_settings,
targets: [approve_app_target, approve_tests_target],
fn approve_ios_project_spec(server_host: NonEmptyStr) -> ProjectSpec {
ProjectSpec {
name: "Approve",
options: approve_project_options,
config_files: [ConfigFile { configuration: "Debug", path: "Config/Team.xcconfig" }, ConfigFile { configuration: "Release", path: "Config/Team.xcconfig" }],
settings: approve_project_settings,
targets: [approve_app_target(server_host: server_host), approve_tests_target],
}
}

type ApproveIosProjectGeneration
Expand All @@ -169,9 +180,27 @@ data approve_ios_project_header: String = join([
""
], "\n")

fn expected_approve_ios_project_yml() -> ApproveIosProjectGeneration {
match emit_yaml(v: project_spec_yaml(p: approve_ios_project_spec)) {
EmittedYaml { text: t } => ApproveIosProjectGenerated { content: concat(approve_ios_project_header, t) }
YamlEmitRefused { path: p, reason: r } => ApproveIosProjectRefused { reason: yaml_emit_refusal_text(module_path: "gunbc.approve_ios_project", path: p, reason: r) }
// THE PROJECTION OVER A SUPPLIED TAILNET DOMAIN AND PUBLIC PORT, so the dependence on the network
// row is a function a claim can exercise rather than a sentence.
//
// A NON-DEFAULT PORT REFUSES RATHER THAN BEING DROPPED. ServerConfig builds https://<host><path>
// and carries no port, so a broker published on another listener would be projected as a host the
// app then dials on 443 -- a plausible address that answers as something else. Carrying the port is
// an Info.plist key plus a ServerConfig field; until a port row exists to need them, the honest arm
// is a refusal naming that.
fn approve_ios_project_yml_from(domain: NonEmptyStr?, port: Port?) -> ApproveIosProjectGeneration {
match port {
Present { value: p } => ApproveIosProjectRefused { reason: join([
"gunbc.approve_ios_project: approval_broker_public_port is ", to_string(p),
" and the app's ServerConfig carries no port; project it (an ApproveServerPort Info.plist key read by gunbc.approve_ios_swift_wire ServerConfig) before publishing the broker off the default TLS listener"
], "") }
Absent => match emit_yaml(v: project_spec_yaml(p: approve_ios_project_spec(server_host: approval_broker_public_host_from(domain: domain)))) {
EmittedYaml { text: t } => ApproveIosProjectGenerated { content: concat(approve_ios_project_header, t) }
YamlEmitRefused { path: p, reason: r } => ApproveIosProjectRefused { reason: yaml_emit_refusal_text(module_path: "gunbc.approve_ios_project", path: p, reason: r) }
}
}
}

fn expected_approve_ios_project_yml() -> ApproveIosProjectGeneration {
approve_ios_project_yml_from(domain: fleet_intent_network.tailnet_domain, port: approval_broker_public_port)
}
Loading