Add production deployment configs for the collab relay and locator: region-split compose (CN/global), direct nginx gateways and location maps, the CN docker-user firewall install/verify/validate tooling and systemd unit, and an SoftHSM-backed locator variant. Extend the collab security/deployment boundary checks to cover the new artifacts. The CN application host address is a placeholder (10.0.0.10); substitute the real private address at deploy time.
655 lines
29 KiB
Bash
655 lines
29 KiB
Bash
# Mutation cases for check-collab-security-boundaries.test.sh.
|
|
# Sourced after the fixture and assertion helpers have been initialized.
|
|
|
|
write_collab_security_workflow_fixture() {
|
|
cat > "$fixture_root/.github/workflows/collab-security.yml" <<'EOF'
|
|
pull_request:
|
|
paths:
|
|
- '.dockerignore'
|
|
- '.gitignore'
|
|
- 'crates/op-collab-smoke/**'
|
|
- 'crates/op-collab-relay-protocol/**'
|
|
- 'crates/op-collab-relay-client/**'
|
|
- 'crates/op-collab-relay-server/**'
|
|
- 'crates/op-collab-relay-control-plane/**'
|
|
- 'crates/op-collab-policy-file/**'
|
|
- 'crates/op-collab-relay-locator-hsm/**'
|
|
- 'crates/op-collab-relay-locator-server/**'
|
|
- 'crates/op-util/**'
|
|
- 'crates/op-editor-core/**'
|
|
- 'crates/op-editor-host-core/**'
|
|
- 'crates/op-editor-ui/**'
|
|
- 'crates/op-host-native/**'
|
|
- 'crates/op-host-desktop/**'
|
|
- 'crates/op-host-services/**'
|
|
- 'crates/op-i18n/**'
|
|
- 'deploy/collab-relay/**'
|
|
- 'deploy/collab-relay-edge/**'
|
|
- 'deploy/collab-relay-locator/**'
|
|
- 'deploy/collab-relay-locator-hsm/**'
|
|
- 'deploy/collab-relay-locator-edge/**'
|
|
- 'tools/check-collab-security-boundaries-cases.sh'
|
|
- 'tools/check-collab-deployment-boundaries.sh'
|
|
- 'tools/check-op-auth-prebuilt.sh'
|
|
- 'tools/check-op-auth-prebuilt.test.sh'
|
|
- 'tools/package-op-auth-prebuilt.sh'
|
|
push:
|
|
paths:
|
|
- '.dockerignore'
|
|
- '.gitignore'
|
|
- 'crates/op-collab-smoke/**'
|
|
- 'crates/op-collab-relay-protocol/**'
|
|
- 'crates/op-collab-relay-client/**'
|
|
- 'crates/op-collab-relay-server/**'
|
|
- 'crates/op-collab-relay-control-plane/**'
|
|
- 'crates/op-collab-policy-file/**'
|
|
- 'crates/op-collab-relay-locator-hsm/**'
|
|
- 'crates/op-collab-relay-locator-server/**'
|
|
- 'crates/op-util/**'
|
|
- 'crates/op-editor-core/**'
|
|
- 'crates/op-editor-host-core/**'
|
|
- 'crates/op-editor-ui/**'
|
|
- 'crates/op-host-native/**'
|
|
- 'crates/op-host-desktop/**'
|
|
- 'crates/op-host-services/**'
|
|
- 'crates/op-i18n/**'
|
|
- 'deploy/collab-relay/**'
|
|
- 'deploy/collab-relay-edge/**'
|
|
- 'deploy/collab-relay-locator/**'
|
|
- 'deploy/collab-relay-locator-hsm/**'
|
|
- 'deploy/collab-relay-locator-edge/**'
|
|
- 'tools/check-collab-security-boundaries-cases.sh'
|
|
- 'tools/check-collab-deployment-boundaries.sh'
|
|
- 'tools/check-op-auth-prebuilt.sh'
|
|
- 'tools/check-op-auth-prebuilt.test.sh'
|
|
- 'tools/package-op-auth-prebuilt.sh'
|
|
steps:
|
|
- run: bash tools/check-op-auth-prebuilt.sh
|
|
- run: bash tools/check-op-auth-prebuilt.test.sh
|
|
- run: bash -n tools/package-op-auth-prebuilt.sh
|
|
- run: cargo test --locked -p op-auth-bridge --test prebuilt_provenance
|
|
- run: cargo test --locked -p op-collab-transport
|
|
- run: cargo test --locked -p op-collab-transport config::tests
|
|
- run: cargo test --locked -p op-collab-transport frame::tests
|
|
- run: cargo test --locked -p op-collab-relay-locator-hsm
|
|
- run: |
|
|
docker build --target test \
|
|
-f deploy/collab-relay-locator-hsm/Dockerfile .
|
|
- run: bash deploy/collab-relay-edge/validate.sh
|
|
- run: bash deploy/collab-relay-locator/validate.sh
|
|
- run: bash deploy/collab-relay-locator-edge/validate.sh
|
|
EOF
|
|
}
|
|
|
|
new_fixture baseline
|
|
expect_pass "accepts the minimal safe collaboration boundary"
|
|
|
|
new_fixture wasm-native-dependency
|
|
: > "$fixture_root/.fake-wasm-forbidden"
|
|
expect_failure "rejects native dependencies in the wasm closure" \
|
|
"WASM boundary includes native/auth dependencies"
|
|
|
|
new_fixture credential-clone-assertion-removed
|
|
sed '/assert_not_impl_any!(OpaqueTicket: Clone);/d' \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs" \
|
|
> "$fixture_root/crates/op-collab/tests/credential_ownership.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs.next" \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs"
|
|
expect_failure "requires compile-time non-Clone credential assertions" \
|
|
"credential-bearing protocol type must remain non-Clone"
|
|
|
|
new_fixture dedicated-ticket-codec-removed
|
|
: > "$fixture_root/crates/op-collab/src/error.rs"
|
|
expect_failure "requires the dedicated credential codec failure" \
|
|
"dedicated credential codec failure"
|
|
|
|
new_fixture credential-preflight-moved-after-value
|
|
awk '
|
|
index($0, " declared_kind_rejecting_renew_ticket(bytes)?;") == 1 {
|
|
held = $0
|
|
next
|
|
}
|
|
held != "" && index($0, " let mut value = decode_json_value(bytes, limits)?;") == 1 {
|
|
print
|
|
print held
|
|
held = ""
|
|
next
|
|
}
|
|
{ print }
|
|
' \
|
|
"$fixture_root/crates/op-collab/src/codec.rs" \
|
|
> "$fixture_root/crates/op-collab/src/codec.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-collab/src/codec.rs.next" \
|
|
"$fixture_root/crates/op-collab/src/codec.rs"
|
|
expect_failure "requires credential classification before generic Value decoding" \
|
|
"generic credential discriminator must run before JSON Value decoding"
|
|
|
|
new_fixture inbound-direction-budget-moved-after-discriminator
|
|
awk '
|
|
index($0, " enforce_inbound_envelope_limit(inbound_direction, bytes.len(), limits)?;") == 1 {
|
|
held = $0
|
|
next
|
|
}
|
|
held != "" && index($0, " declared_kind_rejecting_renew_ticket(bytes)?;") == 1 {
|
|
print
|
|
print held
|
|
held = ""
|
|
next
|
|
}
|
|
{ print }
|
|
' \
|
|
"$fixture_root/crates/op-collab/src/codec.rs" \
|
|
> "$fixture_root/crates/op-collab/src/codec.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-collab/src/codec.rs.next" \
|
|
"$fixture_root/crates/op-collab/src/codec.rs"
|
|
expect_failure "requires trusted direction budgeting before wire discrimination" \
|
|
"trusted per-direction inbound envelope limit must run before discriminator and JSON Value decoding"
|
|
|
|
new_fixture dedicated-ticket-zeroizing-decoder-removed
|
|
sed '/Zeroizing::new(String::with_capacity/d' \
|
|
"$fixture_root/crates/op-collab/src/ticket_json.rs" \
|
|
> "$fixture_root/crates/op-collab/src/ticket_json.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-collab/src/ticket_json.rs.next" \
|
|
"$fixture_root/crates/op-collab/src/ticket_json.rs"
|
|
expect_failure "requires direct zeroizing ticket string decoding" \
|
|
"direct zeroizing ticket string decoder"
|
|
|
|
new_fixture dedicated-ticket-ordinary-string-deserializer
|
|
printf '%s\n' \
|
|
'fn bad() { let _ = String::deserialize(deserializer); }' \
|
|
>> "$fixture_root/crates/op-collab/src/ticket_json.rs"
|
|
expect_failure "rejects ordinary String deserialization in the ticket decoder" \
|
|
"dedicated ticket decoder must not materialize ordinary strings or Values"
|
|
|
|
new_fixture opaque-ticket-generic-string-deserializer
|
|
printf '%s\n' \
|
|
'fn bad() { let _ = String::deserialize(deserializer); }' \
|
|
>> "$fixture_root/crates/op-collab/src/protocol.rs"
|
|
expect_failure "rejects ordinary String deserialization in OpaqueTicket" \
|
|
"OpaqueTicket must not deserialize through an ordinary String"
|
|
|
|
new_fixture generic-renewal-deserialize-assertion-removed
|
|
sed '/assert_not_impl_any!(RenewTicket: serde::de::DeserializeOwned);/d' \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs" \
|
|
> "$fixture_root/crates/op-collab/tests/credential_ownership.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs.next" \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs"
|
|
expect_failure "requires the generic renewal Deserialize compile-time boundary" \
|
|
"credential-bearing protocol type must not implement generic Deserialize"
|
|
|
|
new_fixture derived-collab-message-deserializer
|
|
printf '%s\n' \
|
|
'#[derive(PartialEq, Serialize, Deserialize)]' \
|
|
>> "$fixture_root/crates/op-collab/src/protocol.rs"
|
|
expect_failure "rejects derived adjacent-tag CollabMessage deserialization" \
|
|
"CollabMessage must not use derived Deserialize"
|
|
|
|
new_fixture direct-serde-renewal-serialization-regression-removed
|
|
sed '/direct_serde_renewal_serialization_is_fail_closed/d' \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs" \
|
|
> "$fixture_root/crates/op-collab/tests/credential_ownership.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs.next" \
|
|
"$fixture_root/crates/op-collab/tests/credential_ownership.rs"
|
|
expect_failure "requires the direct serde renewal serialization regression" \
|
|
"direct serde credential serialization rejection test"
|
|
|
|
new_fixture mislabeled-renewal-regression-removed
|
|
: > "$fixture_root/crates/op-collab-transport/src/frame.rs"
|
|
expect_failure "requires the mislabeled renewal transport regression" \
|
|
"mislabeled credential transport regression test"
|
|
|
|
new_fixture credential-transport-workflow-test-removed
|
|
sed '/cargo test --locked -p op-collab-transport frame::tests/d' \
|
|
"$fixture_root/.github/workflows/collab-security.yml" \
|
|
> "$fixture_root/.github/workflows/collab-security.yml.next"
|
|
mv \
|
|
"$fixture_root/.github/workflows/collab-security.yml.next" \
|
|
"$fixture_root/.github/workflows/collab-security.yml"
|
|
expect_failure "requires the credential transport codec workflow test" \
|
|
"credential transport codec workflow test"
|
|
|
|
new_fixture complete-transport-workflow-test-removed
|
|
sed '/cargo test --locked -p op-collab-transport$/d' \
|
|
"$fixture_root/.github/workflows/collab-security.yml" \
|
|
> "$fixture_root/.github/workflows/collab-security.yml.next"
|
|
mv \
|
|
"$fixture_root/.github/workflows/collab-security.yml.next" \
|
|
"$fixture_root/.github/workflows/collab-security.yml"
|
|
expect_failure "requires the complete transport resource-limit test suite" \
|
|
"complete transport resource-limit workflow test"
|
|
|
|
new_fixture locator-hsm-workflow-tests-removed
|
|
sed \
|
|
-e '/cargo test --locked -p op-collab-relay-locator-hsm/d' \
|
|
-e '/docker build --target test/d' \
|
|
"$fixture_root/.github/workflows/collab-security.yml" \
|
|
> "$fixture_root/.github/workflows/collab-security.yml.next"
|
|
mv \
|
|
"$fixture_root/.github/workflows/collab-security.yml.next" \
|
|
"$fixture_root/.github/workflows/collab-security.yml"
|
|
expect_failure "requires locator HSM unit and real SoftHSM workflow tests" \
|
|
"locator HSM crate workflow test"
|
|
|
|
new_fixture locator-hsm-soft-token-target-removed
|
|
sed 's/docker build --target test/docker build/' \
|
|
"$fixture_root/.github/workflows/collab-security.yml" \
|
|
> "$fixture_root/.github/workflows/collab-security.yml.next"
|
|
mv \
|
|
"$fixture_root/.github/workflows/collab-security.yml.next" \
|
|
"$fixture_root/.github/workflows/collab-security.yml"
|
|
expect_failure "requires the real SoftHSM Docker test stage" \
|
|
"real SoftHSM workflow test target"
|
|
|
|
new_fixture locator-hsm-production-seed
|
|
printf '%s\n' \
|
|
'const PRODUCTION_SIGNING_SEED: [u8; 32] = [9; 32];' \
|
|
>> "$fixture_root/crates/op-collab-relay-locator-hsm/src/lib.rs"
|
|
expect_failure "scans the locator HSM crate for deterministic production keys" \
|
|
"deterministic signing/key seed leaked"
|
|
|
|
new_fixture desktop-renewal-vec-copy
|
|
printf '%s\n' \
|
|
'fn bad(ticket: Ticket) { let _ = ticket.expose().as_bytes().to_vec(); }' \
|
|
>> "$fixture_root/crates/op-collab-host/src/runtime/types.rs"
|
|
expect_failure "rejects ordinary Vec copies in desktop renewal commands" \
|
|
"desktop renewal commands must move OpaqueTicket"
|
|
|
|
new_fixture non-mit-crate
|
|
cat > "$fixture_root/crates/op-collab-transport/Cargo.toml" <<'EOF'
|
|
[package]
|
|
name = "op-collab-transport"
|
|
version = "0.0.0"
|
|
license = "Apache-2.0"
|
|
EOF
|
|
expect_failure "rejects a non-MIT collaboration crate" \
|
|
"must inherit or declare the MIT license"
|
|
|
|
new_fixture deterministic-production-seed
|
|
printf '%s\n' \
|
|
'const PRODUCTION_SIGNING_SEED: [u8; 32] = [9; 32];' \
|
|
>> "$fixture_root/crates/op-collab/src/protocol.rs"
|
|
expect_failure "rejects deterministic key material in production source" \
|
|
"deterministic signing/key seed leaked"
|
|
|
|
new_fixture deterministic-production-seed-after-test-module
|
|
printf '%s\n' \
|
|
'const PRODUCTION_SIGNING_SEED: [u8; 32] = [9; 32];' \
|
|
>> "$fixture_root/crates/op-auth-bridge/src/collab_verifier.rs"
|
|
expect_failure "scans production items after an inline cfg(test) module" \
|
|
"deterministic signing/key seed leaked"
|
|
|
|
new_fixture deterministic-external-test-without-cfg
|
|
sed '/#!\[cfg(test)\]/d' \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_jwks_cache_cancellation_tests.rs" \
|
|
> "$fixture_root/crates/op-auth-bridge/src/collab_jwks_cache_cancellation_tests.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_jwks_cache_cancellation_tests.rs.next" \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_jwks_cache_cancellation_tests.rs"
|
|
expect_failure "requires an explicit cfg(test) boundary for external unit tests" \
|
|
"deterministic signing/key seed leaked"
|
|
|
|
new_fixture deterministic-path-test-without-parent-cfg
|
|
sed '/#\[cfg(test)\]/d' \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_jwks_cache.rs" \
|
|
> "$fixture_root/crates/op-auth-bridge/src/collab_jwks_cache.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_jwks_cache.rs.next" \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_jwks_cache.rs"
|
|
expect_failure "requires cfg(test) on path-based external unit-test modules" \
|
|
"deterministic signing/key seed leaked"
|
|
|
|
new_fixture production-root-fixture-regression-removed
|
|
sed '/verifies_the_frozen_go_production_root_fixture/d' \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_union_policy_tests.rs" \
|
|
> "$fixture_root/crates/op-auth-bridge/src/collab_union_policy_tests.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_union_policy_tests.rs.next" \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_union_policy_tests.rs"
|
|
expect_failure "requires the split production root fixture regression" \
|
|
"production trust-root fixture regression test"
|
|
|
|
new_fixture production-policy-fail-closed-regression-removed
|
|
sed '/production_signed_policy_path_never_falls_back_to_raw_jwks/d' \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_verifier.rs" \
|
|
> "$fixture_root/crates/op-auth-bridge/src/collab_verifier.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_verifier.rs.next" \
|
|
"$fixture_root/crates/op-auth-bridge/src/collab_verifier.rs"
|
|
expect_failure "requires the split production policy fail-closed regression" \
|
|
"production/test issuer isolation regression test"
|
|
|
|
new_fixture sensitive-key-file
|
|
: > "$fixture_root/crates/op-collab-transport/peer.key"
|
|
expect_failure "rejects key-shaped repository fixtures" \
|
|
"sensitive key/token-shaped files are forbidden"
|
|
|
|
new_fixture sealed-relay-key-json
|
|
: > "$fixture_root/deploy/collab-relay/relay-x25519-keys.json"
|
|
expect_failure "rejects sealed Relay private-key JSON in the repository" \
|
|
"sensitive key/token-shaped files are forbidden"
|
|
|
|
new_fixture relay-key-dockerignore-removed
|
|
sed '/relay-x25519-keys/d' \
|
|
"$fixture_root/.dockerignore" \
|
|
> "$fixture_root/.dockerignore.next"
|
|
mv "$fixture_root/.dockerignore.next" "$fixture_root/.dockerignore"
|
|
expect_failure "requires private Relay key JSON exclusion from Docker builds" \
|
|
"Docker build-context private-key exclusion"
|
|
|
|
new_fixture relay-key-gitignore-removed
|
|
sed '/relay-x25519-keys/d' \
|
|
"$fixture_root/.gitignore" \
|
|
> "$fixture_root/.gitignore.next"
|
|
mv "$fixture_root/.gitignore.next" "$fixture_root/.gitignore"
|
|
expect_failure "requires private Relay key JSON exclusion from Git staging" \
|
|
"Git private-key exclusion"
|
|
|
|
new_fixture compact-token
|
|
mkdir -p "$fixture_root/crates/op-collab/fixtures"
|
|
printf '%s\n' \
|
|
'"abcdefghijklmnop.qrstuvwxyzABCDEF.abcdefghijklmnopqrstuvwxyzABCDEF0123456789"' \
|
|
> "$fixture_root/crates/op-collab/fixtures/captured-ticket.txt"
|
|
expect_failure "rejects compact bearer tokens in non-source fixtures" \
|
|
"high-signal credential/private-key material detected"
|
|
|
|
new_fixture smoke-compact-token
|
|
printf '%s\n' \
|
|
'"abcdefghijklmnop.qrstuvwxyzABCDEF.abcdefghijklmnopqrstuvwxyzABCDEF0123456789"' \
|
|
> "$fixture_root/crates/op-collab-smoke/captured-ticket.txt"
|
|
expect_failure "rejects compact bearer tokens in the smoke crate" \
|
|
"high-signal credential/private-key material detected"
|
|
|
|
new_fixture desktop-sensitive-file
|
|
: > "$fixture_root/crates/op-collab-host/src/runtime/runtime-ticket.token"
|
|
expect_failure "rejects sensitive files in desktop collaboration integration" \
|
|
"sensitive key/token-shaped files are forbidden"
|
|
|
|
new_fixture avatar-redirect-limit-removed
|
|
sed '/MAX_REDIRECTS/d' \
|
|
"$fixture_root/crates/op-host-services/src/profile_avatar_fetch.rs" \
|
|
> "$fixture_root/crates/op-host-services/src/profile_avatar_fetch.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-host-services/src/profile_avatar_fetch.rs.next" \
|
|
"$fixture_root/crates/op-host-services/src/profile_avatar_fetch.rs"
|
|
expect_failure "requires the shared avatar redirect limit" \
|
|
"bounded collaboration avatar fetch"
|
|
|
|
new_fixture desktop-public-avatar-delegation-removed
|
|
sed '/fetch_profile_avatar_blocking(request.url())/d' \
|
|
"$fixture_root/crates/op-host-desktop/src/collab_avatar_host.rs" \
|
|
> "$fixture_root/crates/op-host-desktop/src/collab_avatar_host.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-host-desktop/src/collab_avatar_host.rs.next" \
|
|
"$fixture_root/crates/op-host-desktop/src/collab_avatar_host.rs"
|
|
expect_failure "requires public-only desktop collaboration avatar delegation" \
|
|
"desktop avatar security-policy delegation"
|
|
|
|
new_fixture avatar-proxy-bypass-removed
|
|
: > "$fixture_root/crates/op-host-services/src/provider_dial.rs"
|
|
expect_failure "requires proxy-free pinned avatar dialing" \
|
|
"public HTTPS proxy bypass prevention"
|
|
|
|
new_fixture auth-artifact-integrity-removed
|
|
: > "$fixture_root/crates/op-auth-bridge/build.rs"
|
|
expect_failure "requires authentication artifact integrity verification" \
|
|
"authentication artifact integrity gate"
|
|
|
|
new_fixture auth-artifact-signature-removed
|
|
: > "$fixture_root/crates/op-auth-bridge/prebuilt_provenance.rs"
|
|
expect_failure "requires authentication artifact signature verification" \
|
|
"authentication artifact signature verification"
|
|
|
|
new_fixture auth-matrix-test-removed
|
|
sed \
|
|
'/cargo test --locked -p op-auth-bridge --test prebuilt_provenance/d' \
|
|
"$fixture_root/.github/workflows/collab-security.yml" \
|
|
> "$fixture_root/.github/workflows/collab-security.yml.next"
|
|
mv \
|
|
"$fixture_root/.github/workflows/collab-security.yml.next" \
|
|
"$fixture_root/.github/workflows/collab-security.yml"
|
|
expect_failure "requires the committed authentication matrix test" \
|
|
"committed authentication matrix test"
|
|
|
|
new_fixture integration-line-cap
|
|
awk 'BEGIN { for (line = 1; line <= 801; line++) print "// integration line" }' \
|
|
> "$fixture_root/crates/op-editor-host-core/src/collab/oversized.rs"
|
|
expect_failure "enforces the line cap across collaboration integration source" \
|
|
"has 801 lines; maximum is 800"
|
|
|
|
new_fixture missing-workflow-trigger
|
|
awk '
|
|
!removed && index($0, "crates/op-host-desktop/**") {
|
|
removed = 1
|
|
next
|
|
}
|
|
{ print }
|
|
' \
|
|
"$fixture_root/.github/workflows/collab-security.yml" \
|
|
> "$fixture_root/.github/workflows/collab-security.yml.next"
|
|
mv \
|
|
"$fixture_root/.github/workflows/collab-security.yml.next" \
|
|
"$fixture_root/.github/workflows/collab-security.yml"
|
|
expect_failure "rejects removal of either integration workflow trigger" \
|
|
"collaboration security workflow path trigger"
|
|
|
|
new_fixture relay-edge-mtls-verification-removed
|
|
sed '/proxy_ssl_verify on;/d' \
|
|
"$fixture_root/deploy/collab-relay-edge/global-nginx.conf" \
|
|
> "$fixture_root/deploy/collab-relay-edge/global-nginx.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-edge/global-nginx.conf.next" \
|
|
"$fixture_root/deploy/collab-relay-edge/global-nginx.conf"
|
|
expect_failure "requires Global-to-CN outer-mTLS server verification" \
|
|
"Global-to-CN inner-TLS passthrough boundary"
|
|
|
|
new_fixture relay-edge-client-crl-removed
|
|
awk '!index($0, "ssl_crl /run/secrets/global-edge-client-crl.pem;")' \
|
|
"$fixture_root/deploy/collab-relay-edge/cn-federation-nginx.conf" \
|
|
> "$fixture_root/deploy/collab-relay-edge/cn-federation-nginx.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-edge/cn-federation-nginx.conf.next" \
|
|
"$fixture_root/deploy/collab-relay-edge/cn-federation-nginx.conf"
|
|
expect_failure "requires revocation checking for Global edge client certificates" \
|
|
"CN outer-mTLS federation boundary"
|
|
|
|
new_fixture relay-edge-crl-production-validation-removed
|
|
sed '/OPENPENCIL_RELAY_EDGE_VALIDATION_MODE=production/d' \
|
|
"$fixture_root/deploy/collab-relay-edge/rotate-cn-crl.sh" \
|
|
> "$fixture_root/deploy/collab-relay-edge/rotate-cn-crl.sh.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-edge/rotate-cn-crl.sh.next" \
|
|
"$fixture_root/deploy/collab-relay-edge/rotate-cn-crl.sh"
|
|
expect_failure "requires production validation before Relay CRL activation" \
|
|
"relay federation CRL activation boundary"
|
|
|
|
new_fixture relay-edge-source-rate-removed
|
|
awk '!index($0, "limit rate over 60/minute burst 20 packets")' \
|
|
"$fixture_root/deploy/collab-relay-edge/install-global-new-connection-rate.sh" \
|
|
> "$fixture_root/deploy/collab-relay-edge/install-global-new-connection-rate.sh.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-edge/install-global-new-connection-rate.sh.next" \
|
|
"$fixture_root/deploy/collab-relay-edge/install-global-new-connection-rate.sh"
|
|
expect_failure "requires the overseas relay per-source connection-rate gate" \
|
|
"overseas relay per-source connection-rate boundary"
|
|
|
|
new_fixture relay-edge-auto-restart-enabled
|
|
sed 's/restart: "no"/restart: unless-stopped/' \
|
|
"$fixture_root/deploy/collab-relay-edge/compose.global.yaml" \
|
|
> "$fixture_root/deploy/collab-relay-edge/compose.global.yaml.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-edge/compose.global.yaml.next" \
|
|
"$fixture_root/deploy/collab-relay-edge/compose.global.yaml"
|
|
expect_failure "requires supervised relay startup after the nftables gate" \
|
|
"overseas relay supervised fixed-port boundary"
|
|
|
|
new_fixture relay-edge-verifier-not-executable
|
|
chmod -x "$fixture_root/deploy/collab-relay-edge/verify-rate-rules.py"
|
|
expect_failure "requires executable deployment gate helpers" \
|
|
"deployment gate executable boundary"
|
|
|
|
new_fixture relay-bearer-header-buffer-removed
|
|
awk '
|
|
!removed && /client_header_buffer_size 64k;/ {
|
|
removed = 1
|
|
next
|
|
}
|
|
{ print }
|
|
' \
|
|
"$fixture_root/deploy/collab-relay/nginx.conf" \
|
|
> "$fixture_root/deploy/collab-relay/nginx.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay/nginx.conf.next" \
|
|
"$fixture_root/deploy/collab-relay/nginx.conf"
|
|
expect_failure "requires 48 KiB bearer buffers on both relay ingresses" \
|
|
"48 KiB relay bearer ingress header boundary"
|
|
|
|
new_fixture cn-federation-aggregate-limit-removed
|
|
sed '/limit_conn relay_federation_connections 512;/d' \
|
|
"$fixture_root/deploy/collab-relay/nginx.conf" \
|
|
> "$fixture_root/deploy/collab-relay/nginx.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay/nginx.conf.next" \
|
|
"$fixture_root/deploy/collab-relay/nginx.conf"
|
|
expect_failure "keeps the trusted federation backhaul off the public per-IP ceiling" \
|
|
"CN WSS/federation ingress boundary"
|
|
|
|
new_fixture locator-hsm-boundary-removed
|
|
sed '/OPENPENCIL_COLLAB_LOCATOR_HSM_SOCKET:/d' \
|
|
"$fixture_root/deploy/collab-relay-locator/compose.yaml" \
|
|
> "$fixture_root/deploy/collab-relay-locator/compose.yaml.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-locator/compose.yaml.next" \
|
|
"$fixture_root/deploy/collab-relay-locator/compose.yaml"
|
|
expect_failure "requires the external locator HSM socket boundary" \
|
|
"locator production container boundary"
|
|
|
|
new_fixture locator-per-source-limit-removed
|
|
sed '/limit_req_zone.*openpencil_locator_per_source/d' \
|
|
"$fixture_root/deploy/collab-relay-locator/nginx-http-limits.conf" \
|
|
> "$fixture_root/deploy/collab-relay-locator/nginx-http-limits.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-locator/nginx-http-limits.conf.next" \
|
|
"$fixture_root/deploy/collab-relay-locator/nginx-http-limits.conf"
|
|
expect_failure "requires per-source locator ingress throttling" \
|
|
"locator per-source ingress boundary"
|
|
|
|
new_fixture locator-pairing-route-removed
|
|
awk '!index($0, "location = /v1/pairing-code {")' \
|
|
"$fixture_root/deploy/collab-relay-locator/nginx-location.conf" \
|
|
> "$fixture_root/deploy/collab-relay-locator/nginx-location.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-locator/nginx-location.conf.next" \
|
|
"$fixture_root/deploy/collab-relay-locator/nginx-location.conf"
|
|
expect_failure "requires the pairing publish route at the locator ingress" \
|
|
"locator exact-route ingress boundary"
|
|
|
|
new_fixture locator-edge-crl-secure-ownership-removed
|
|
awk '!index($0, "CRL/CA files must be root:101 mode 0440")' \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/rotate-cn-crl.sh" \
|
|
> "$fixture_root/deploy/collab-relay-locator-edge/rotate-cn-crl.sh.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/rotate-cn-crl.sh.next" \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/rotate-cn-crl.sh"
|
|
expect_failure "requires secure ownership before locator CRL activation" \
|
|
"locator federation CRL activation boundary"
|
|
|
|
new_fixture mutable-relay-container-base
|
|
awk '
|
|
/^FROM rust:/ {
|
|
print "FROM rust:1.94-bookworm AS build"
|
|
next
|
|
}
|
|
{ print }
|
|
' \
|
|
"$fixture_root/deploy/collab-relay/Dockerfile" \
|
|
> "$fixture_root/deploy/collab-relay/Dockerfile.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay/Dockerfile.next" \
|
|
"$fixture_root/deploy/collab-relay/Dockerfile"
|
|
expect_failure "requires immutable digests for relay container base images" \
|
|
"relay container base images must use reviewed immutable SHA-256 digests"
|
|
|
|
new_fixture locator-edge-mtls-verification-removed
|
|
sed '/proxy_ssl_verify on;/d' \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/global-nginx.conf" \
|
|
> "$fixture_root/deploy/collab-relay-locator-edge/global-nginx.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/global-nginx.conf.next" \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/global-nginx.conf"
|
|
expect_failure "requires outer-mTLS verification on the overseas locator ingress" \
|
|
"overseas locator inner-TLS passthrough boundary"
|
|
|
|
new_fixture locator-edge-exact-host-removed
|
|
awk '!index($0, "if ($http_host != locator.example.cn) {")' \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/cn-locator-https-nginx.conf" \
|
|
> "$fixture_root/deploy/collab-relay-locator-edge/cn-locator-https-nginx.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/cn-locator-https-nginx.conf.next" \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/cn-locator-https-nginx.conf"
|
|
expect_failure "requires an exact inner HTTPS Host at the CN locator terminator" \
|
|
"CN locator exact inner-HTTPS boundary"
|
|
|
|
new_fixture locator-edge-pairing-claim-route-removed
|
|
awk '!index($0, "location = /v1/pairing-code/claim {")' \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/cn-locator-https-nginx.conf" \
|
|
> "$fixture_root/deploy/collab-relay-locator-edge/cn-locator-https-nginx.conf.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/cn-locator-https-nginx.conf.next" \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/cn-locator-https-nginx.conf"
|
|
expect_failure "requires the pairing claim route at the CN locator terminator" \
|
|
"CN locator exact inner-HTTPS boundary"
|
|
|
|
new_fixture locator-edge-source-rate-removed
|
|
awk '!index($0, "limit rate over 60/minute burst 20 packets")' \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/install-global-new-connection-rate.sh" \
|
|
> "$fixture_root/deploy/collab-relay-locator-edge/install-global-new-connection-rate.sh.next"
|
|
mv \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/install-global-new-connection-rate.sh.next" \
|
|
"$fixture_root/deploy/collab-relay-locator-edge/install-global-new-connection-rate.sh"
|
|
expect_failure "requires the overseas locator per-source connection-rate gate" \
|
|
"overseas locator per-source connection-rate boundary"
|
|
|
|
new_fixture missing-hard-limit
|
|
awk '!/MAX_OPS_PER_TXN/' \
|
|
"$fixture_root/crates/op-collab/src/protocol.rs" \
|
|
> "$fixture_root/crates/op-collab/src/protocol.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-collab/src/protocol.rs.next" \
|
|
"$fixture_root/crates/op-collab/src/protocol.rs"
|
|
expect_failure "rejects removal of a protocol hard-limit anchor" \
|
|
"protocol hard limit"
|
|
|
|
new_fixture public-transport-queue
|
|
sed \
|
|
's/pub(crate) struct BoundedTransferQueue/pub struct BoundedTransferQueue/' \
|
|
"$fixture_root/crates/op-collab-transport/src/queue.rs" \
|
|
> "$fixture_root/crates/op-collab-transport/src/queue.rs.next"
|
|
mv \
|
|
"$fixture_root/crates/op-collab-transport/src/queue.rs.next" \
|
|
"$fixture_root/crates/op-collab-transport/src/queue.rs"
|
|
expect_failure "rejects exposing the transport queue implementation" \
|
|
"bounded queue/rate type"
|
|
|
|
new_fixture untyped-boundary-error
|
|
printf '%s\n' \
|
|
'fn bad_boundary() -> Result<(), String> { Ok(()) }' \
|
|
>> "$fixture_root/crates/op-collab/src/protocol.rs"
|
|
expect_failure "rejects untyped public boundary errors" \
|
|
"untyped Result<_, String/&str>"
|
|
|
|
if [[ "$failure_count" -ne 0 ]]; then
|
|
printf '%s\n' \
|
|
"check-collab-security-boundaries.test.sh: $failure_count mutation test(s) failed." \
|
|
>&2
|
|
exit 1
|
|
fi
|
|
|
|
printf '%s\n' \
|
|
"check-collab-security-boundaries.test.sh: all $test_index mutation tests pass."
|