mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 04:33:17 +00:00
Restore returned demo recovery candidate for complete footprint repair
Retain the independently rejected distribution-state rollback evidence and repair the operation in this assigned worktree; canonical publication remains separate. Change-source: pulse-maintainer
This commit is contained in:
@@ -2306,7 +2306,11 @@ func TestUpdateDemoWorkflowUsesGovernedNetworkPath(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("read demo runtime profile resolver: %v", err)
|
||||
}
|
||||
workflow := string(workflowBytes) + "\n" + string(profileBytes)
|
||||
transactionBytes, err := os.ReadFile(repoFile(".github", "scripts", "demo-runtime-transaction.py"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
workflow := string(workflowBytes) + "\n" + string(profileBytes) + "\n" + string(transactionBytes)
|
||||
required := []string{
|
||||
`- name: Tailscale`,
|
||||
`uses: tailscale/github-action@780049a30b6ff5c378a9e7b389d15ece7a204888 # v4.1.3`,
|
||||
@@ -2319,7 +2323,6 @@ func TestUpdateDemoWorkflowUsesGovernedNetworkPath(t *testing.T) {
|
||||
`workflow_call:`,
|
||||
`verify_only:`,
|
||||
`Waiting for activated release assets to be available`,
|
||||
`bash /tmp/pulse-install.sh --version "$TAG"`,
|
||||
`Refuse mutation during verification-only checks`,
|
||||
`uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0`,
|
||||
`go run ./scripts/release_update_key.go public-key-ssh`,
|
||||
@@ -2327,15 +2330,10 @@ func TestUpdateDemoWorkflowUsesGovernedNetworkPath(t *testing.T) {
|
||||
`Verify target host identity`,
|
||||
`bash .github/scripts/setup-demo-ssh.sh`,
|
||||
`Demo environment points at host $REMOTE_HOSTNAME but expected $DEMO_EXPECTED_HOSTNAME.`,
|
||||
`Prepare demo host storage`,
|
||||
`KEEP_BACKUPS=2`,
|
||||
`Removing demo backup to restore install headroom: %s`,
|
||||
`Pruning demo volatile runtime stores to restore install headroom.`,
|
||||
`sudo find "$CONFIG_DIR" -xdev -type f`,
|
||||
`-name "metrics.db"`,
|
||||
`Removing demo volatile store: %s`,
|
||||
`Demo host does not have enough free space to back up $CONFIG_DIR before install.`,
|
||||
`Restore demo runtime configuration`,
|
||||
`Apply guarded demo transaction`,
|
||||
`python3 .github/scripts/dispatch-demo-runtime.py "$MODE"`,
|
||||
`Retain guarded demo transaction evidence`,
|
||||
`.forward.elapsed_seconds >= 300`,
|
||||
`Resolve target-compatible demo runtime profile`,
|
||||
`git grep -q 'mockEagerHistoryPVEGuestLimit'`,
|
||||
`git grep -q 'UpdateMetricCohort'`,
|
||||
@@ -2361,22 +2359,13 @@ func TestUpdateDemoWorkflowUsesGovernedNetworkPath(t *testing.T) {
|
||||
`MOCK_SEED_DURATION=2h`,
|
||||
`MOCK_SAMPLE_INTERVAL=5m`,
|
||||
`MOCK_UPDATE_INTERVAL=15s`,
|
||||
`resolve_config_dir`,
|
||||
`set_env_value DEMO_MODE true`,
|
||||
`set_env_value PULSE_MOCK_MODE true`,
|
||||
`set_env_value PULSE_MOCK_NODES "$MOCK_NODES"`,
|
||||
`set_env_value PULSE_MOCK_VMS_PER_NODE "$MOCK_VMS_PER_NODE"`,
|
||||
`set_env_value PULSE_MOCK_LXCS_PER_NODE "$MOCK_LXCS_PER_NODE"`,
|
||||
`set_env_value PULSE_MOCK_DOCKER_HOSTS "$MOCK_DOCKER_HOSTS"`,
|
||||
`set_env_value PULSE_MOCK_K8S_PODS "$MOCK_K8S_PODS"`,
|
||||
`set_env_value PULSE_MOCK_SEED_METRICS_STORE false`,
|
||||
`set_env_value PULSE_MOCK_TRENDS_SEED_DURATION "$MOCK_SEED_DURATION"`,
|
||||
`set_env_value PULSE_MOCK_TRENDS_SAMPLE_INTERVAL "$MOCK_SAMPLE_INTERVAL"`,
|
||||
`set_env_value PULSE_MOCK_UPDATE_INTERVAL "$MOCK_UPDATE_INTERVAL"`,
|
||||
`ensure_demo_fixture_entitlement`,
|
||||
`"demo_fixtures"`,
|
||||
`del(.integrity)`,
|
||||
`Demo fixture entitlement ensured in governed demo billing state.`,
|
||||
`WINDOW = 300`,
|
||||
`/var/lib/pulse-deploy/relay/deploy.lock`,
|
||||
`snapshot-headroom`,
|
||||
`restored-estate-identity`,
|
||||
`demo_fixtures`,
|
||||
`PULSE_MOCK_SEED_METRICS_STORE`,
|
||||
`installer-identity`,
|
||||
`/api/license/runtime-capabilities`,
|
||||
`Mock mode enabled`,
|
||||
`Demo server mock mode did not enable after entitlement sync`,
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package installtests
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDemoTransactionConnectedRecoveryControls(t *testing.T) {
|
||||
cmd := exec.Command("python3", repoFile(".github", "scripts", "tests", "test_demo_runtime_transaction.py"))
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("demo connected transaction controls failed: %v\n%s", err, output)
|
||||
}
|
||||
if !strings.Contains(string(output), "\nOK\n") {
|
||||
t.Fatalf("demo controls did not return a complete unittest verdict: %s", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDemoTransactionKeepsSignedAdmissionAndVerificationOnlyReadOnly(t *testing.T) {
|
||||
workflow, err := os.ReadFile(repoFile(".github", "workflows", "update-demo-server.yml"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
text := string(workflow)
|
||||
start := strings.Index(text, "- name: Apply guarded demo transaction")
|
||||
if start < 0 {
|
||||
t.Fatal("missing retained demo transaction entry")
|
||||
}
|
||||
end := strings.Index(text[start:], "- name: Retain guarded demo transaction evidence")
|
||||
if end < 0 {
|
||||
t.Fatal("missing retained demo transaction entry")
|
||||
}
|
||||
entry := text[start : start+end]
|
||||
if !strings.Contains(entry, "if: inputs.verify_only != true") {
|
||||
t.Fatal("verification-only invocation must never submit a transaction")
|
||||
}
|
||||
for _, forbidden := range []string{"Pruning demo volatile runtime stores", "Removing demo backup to restore install headroom", "sudo systemctl restart"} {
|
||||
if strings.Contains(text, forbidden) {
|
||||
t.Fatalf("unguarded demo mutation remains: %s", forbidden)
|
||||
}
|
||||
}
|
||||
for _, required := range []string{"Require exact committed activation marker for mutation", "release-activation.json", "Stable demo mutation refuses mutable, inactive, or prerelease tag", "PINNED_RELEASE_SSH_PUBLIC_KEY", "git show \"refs/tags/${TAG}:install.sh\"", "Verify public browser smoke"} {
|
||||
if !strings.Contains(text, required) {
|
||||
t.Fatalf("lost signed/admission/customer verification boundary: %s", required)
|
||||
}
|
||||
}
|
||||
recovery, err := os.ReadFile(repoFile(".github", "workflows", "recover-demo-server.yml"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(string(recovery), "sudo systemctl stop pulse") || strings.Contains(string(recovery), "Compensate failed mutated recovery") {
|
||||
t.Fatal("later workflow failure must not stop a committed or unrelated service")
|
||||
}
|
||||
if !strings.Contains(string(recovery), ".forward.elapsed_seconds >= 300") || !strings.Contains(string(recovery), "if: always()") {
|
||||
t.Fatal("recovery must validate and retain the actual terminal observation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDemoNativeAcceptanceIsSecretFreeDisposableAndKeepsRealWindows(t *testing.T) {
|
||||
data, err := os.ReadFile(repoFile(".github", "workflows", "demo-runtime-native.yml"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
text := string(data)
|
||||
for _, required := range []string{
|
||||
"pull_request:", "branches: [main]", "contents: read", "runs-on: ubuntu-24.04", "timeout-minutes: 35",
|
||||
"persist-credentials: false", "actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1",
|
||||
"demo_runtime_native.py", "if: always()", "demo-native-result.json", "if-no-files-found: error",
|
||||
} {
|
||||
if !strings.Contains(text, required) {
|
||||
t.Fatalf("lost disposable native CI/source or terminal-receipt boundary: %s", required)
|
||||
}
|
||||
}
|
||||
for _, forbidden := range []string{"secrets.", "pull_request_target", "self-hosted", "contents: write", "id-token: write"} {
|
||||
if strings.Contains(text, forbidden) {
|
||||
t.Fatalf("native fixture gained credentials, privileged trigger or non-disposable target: %s", forbidden)
|
||||
}
|
||||
}
|
||||
driver, err := os.ReadFile(repoFile(".github", "scripts", "tests", "demo_runtime_native.py"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, required := range []string{"not-an-empty-disposable-public-ci-runner", "dispatcher.BOOTSTRAP", "proc.terminate()", "--signal=TERM", "original_engine_sha256", "fixture_engine_sha256", "cleanup_complete", "signed_published_installer_acceptance", "elapsed_seconds\"] >= 300"} {
|
||||
if !strings.Contains(string(driver), required) {
|
||||
t.Fatalf("lost native fixture observation or limitation: %s", required)
|
||||
}
|
||||
}
|
||||
if strings.Contains(string(driver), "WINDOW =") || strings.Contains(string(driver), "time.monotonic =") || strings.Contains(string(driver), "time.sleep =") {
|
||||
t.Fatal("native acceptance must not shorten production windows or replace real clocks")
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,32 @@ class RegistryAuditTest(unittest.TestCase):
|
||||
args = parse_args(["--check", "--repo-scope", "pulse"])
|
||||
self.assertEqual(args.repo_scope, ["pulse"])
|
||||
|
||||
def test_live_registry_path_lists_are_casefold_sorted(self) -> None:
|
||||
# Fixture-only audit tests cannot catch ordering mistakes in the
|
||||
# committed registry. Check its real path lists using the same
|
||||
# case-insensitive contract as candidate preflight, not ASCII order.
|
||||
registry = registry_audit.load_registry_payload()
|
||||
for subsystem in registry["subsystems"]:
|
||||
lists = {
|
||||
field: subsystem[field]
|
||||
for field in ("owned_prefixes", "owned_files")
|
||||
}
|
||||
verification = subsystem["verification"]
|
||||
lists.update({
|
||||
f"verification.{field}": verification[field]
|
||||
for field in ("test_prefixes", "exact_files")
|
||||
})
|
||||
for policy in verification["path_policies"]:
|
||||
lists.update({
|
||||
f"{policy['id']}.{field}": policy[field]
|
||||
for field in (
|
||||
"match_prefixes", "match_files", "test_prefixes", "exact_files"
|
||||
)
|
||||
})
|
||||
for field, paths in lists.items():
|
||||
with self.subTest(subsystem=subsystem["id"], field=field):
|
||||
self.assertEqual(paths, sorted(paths, key=str.casefold))
|
||||
|
||||
def test_trust_gate_regression_proofs_are_registered_to_exact_policies(self) -> None:
|
||||
registry = registry_audit.load_registry_payload()
|
||||
rules = {rule["id"]: rule for rule in registry["subsystems"]}
|
||||
|
||||
@@ -2589,7 +2589,9 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||
self.assertIn("DEMO_EXPECTED_HOSTNAME", demo)
|
||||
self.assertIn("Verify target host identity", demo)
|
||||
self.assertIn("Demo environment points at host $REMOTE_HOSTNAME but expected $DEMO_EXPECTED_HOSTNAME.", demo)
|
||||
self.assertIn("Restore demo runtime configuration", demo)
|
||||
self.assertIn("Apply guarded demo transaction", demo)
|
||||
self.assertIn("dispatch-demo-runtime.py", demo)
|
||||
self.assertIn("Retain guarded demo transaction evidence", demo)
|
||||
self.assertIn("Resolve target-compatible demo runtime profile", demo)
|
||||
self.assertIn("mockEagerHistoryPVEGuestLimit", demo_profile)
|
||||
self.assertIn("UpdateMetricCohort", demo_profile)
|
||||
@@ -2608,19 +2610,17 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||
self.assertIn("MOCK_SEED_DURATION=2h", demo_profile)
|
||||
self.assertIn("MOCK_SAMPLE_INTERVAL=5m", demo_profile)
|
||||
self.assertIn("MOCK_UPDATE_INTERVAL=15s", demo_profile)
|
||||
self.assertIn("resolve_config_dir", demo)
|
||||
self.assertIn("set_env_value DEMO_MODE true", demo)
|
||||
self.assertIn("set_env_value PULSE_MOCK_MODE true", demo)
|
||||
self.assertIn('set_env_value PULSE_MOCK_NODES "$MOCK_NODES"', demo)
|
||||
self.assertIn("set_env_value PULSE_MOCK_SEED_METRICS_STORE false", demo)
|
||||
self.assertIn('set_env_value PULSE_MOCK_TRENDS_SEED_DURATION "$MOCK_SEED_DURATION"', demo)
|
||||
self.assertIn('set_env_value PULSE_MOCK_TRENDS_SAMPLE_INTERVAL "$MOCK_SAMPLE_INTERVAL"', demo)
|
||||
self.assertIn('set_env_value PULSE_MOCK_UPDATE_INTERVAL "$MOCK_UPDATE_INTERVAL"', demo)
|
||||
self.assertIn("ensure_demo_fixture_entitlement", demo)
|
||||
self.assertIn('"demo_fixtures"', demo)
|
||||
self.assertIn("del(.integrity)", demo)
|
||||
self.assertIn("Demo fixture entitlement ensured in governed demo billing state.", demo)
|
||||
self.assertIn("Demo service restarted with governed demo runtime configuration.", demo)
|
||||
# Profile application moved into the owned transaction; keep its
|
||||
# runtime settings and entitlement, not the superseded shell snippets.
|
||||
transaction = read(".github/scripts/demo-runtime-transaction.py")
|
||||
for required in ('"DEMO_MODE": "true"', '"PULSE_MOCK_MODE": "true"',
|
||||
'"PULSE_MOCK_SEED_METRICS_STORE": "false"',
|
||||
'"seed_duration": "trends_seed_duration"', '"sample_interval": "trends_sample_interval"',
|
||||
'"PULSE_MOCK_" + key.upper()', '["demo_fixtures"]', 'billing.pop("integrity", None)',
|
||||
'self.host.profile(self.request, not healthy_baseline)', 'self.host.start()'):
|
||||
self.assertIn(required, transaction)
|
||||
self.assertIn("MOCK_NODES: ${{ needs.resolve.outputs.mock_nodes }}", demo)
|
||||
self.assertIn("MOCK_UPDATE_INTERVAL: ${{ needs.resolve.outputs.mock_update_interval }}", demo)
|
||||
self.assertIn("/api/license/runtime-capabilities", demo)
|
||||
self.assertIn("Mock mode enabled", demo)
|
||||
self.assertIn("Demo server mock mode did not enable after entitlement sync", demo)
|
||||
@@ -2749,73 +2749,42 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||
def test_stable_demo_recovery_is_fixed_current_bits_only(self) -> None:
|
||||
workflow = read(".github/workflows/recover-demo-server.yml")
|
||||
recovery = read(".github/scripts/recover-demo-runtime.sh")
|
||||
transaction = read(".github/scripts/demo-runtime-transaction.py")
|
||||
dispatcher = read(".github/scripts/dispatch-demo-runtime.py")
|
||||
|
||||
self.assertIn("workflow_dispatch:", workflow)
|
||||
self.assertNotIn("workflow_call:", workflow)
|
||||
self.assertNotIn("inputs:", workflow)
|
||||
self.assertIn("environment: demo-stable", workflow)
|
||||
self.assertIn("contents: read", workflow)
|
||||
self.assertIn("cancel-in-progress: false", workflow)
|
||||
self.assertIn('gh api "repos/${GITHUB_REPOSITORY}/releases/latest"', workflow)
|
||||
self.assertIn("Resolve target-compatible recovery profile", workflow)
|
||||
self.assertIn("resolve-demo-runtime-profile.sh", workflow)
|
||||
self.assertIn(".github/scripts/recover-demo-runtime.sh", workflow)
|
||||
self.assertIn("Verify public health", workflow)
|
||||
self.assertIn("Verify public frontend parity", workflow)
|
||||
self.assertIn("./scripts/run_demo_public_browser_smoke.sh", workflow)
|
||||
self.assertIn("Compensate failed mutated recovery", workflow)
|
||||
self.assertIn("Capture bounded Pulse failure diagnostics", workflow)
|
||||
self.assertIn("demo-runtime-diagnostics.txt", workflow)
|
||||
self.assertIn("journalctl -u pulse --since '-30 minutes'", workflow)
|
||||
self.assertIn("journalctl -u pulse --since '-10 minutes'", workflow)
|
||||
self.assertIn("tail -400", workflow)
|
||||
self.assertIn("sudo systemctl stop pulse", workflow)
|
||||
self.assertIn("Retain bounded recovery evidence", workflow)
|
||||
self.assertNotIn("release-convergence.yml", workflow)
|
||||
self.assertNotIn("install.sh", workflow)
|
||||
self.assertNotIn("scp ", workflow)
|
||||
for required in ("workflow_dispatch:", "environment: demo-stable", "contents: read",
|
||||
"cancel-in-progress: false", 'gh api "repos/${GITHUB_REPOSITORY}/releases/latest"',
|
||||
"Resolve target-compatible recovery profile", "resolve-demo-runtime-profile.sh",
|
||||
".github/scripts/recover-demo-runtime.sh", "Verify public health",
|
||||
"Verify public frontend parity", "./scripts/run_demo_public_browser_smoke.sh",
|
||||
"Capture bounded Pulse failure diagnostics", "demo-runtime-diagnostics.txt",
|
||||
"journalctl -u pulse --since '-30 minutes'", "journalctl -u pulse --since '-10 minutes'",
|
||||
"tail -400", "Retain bounded recovery evidence", ".forward.elapsed_seconds >= 300"):
|
||||
self.assertIn(required, workflow)
|
||||
for forbidden in ("workflow_call:", "inputs:", "release-convergence.yml", "install.sh", "scp ",
|
||||
"Compensate failed mutated recovery", "sudo systemctl stop pulse"):
|
||||
self.assertNotIn(forbidden, workflow)
|
||||
self.assertIn('exec python3 .github/scripts/dispatch-demo-runtime.py recover', recovery)
|
||||
self.assertIn("if mode == 'update' else b''", dispatcher)
|
||||
self.assertIn("/var/lib/pulse-deploy/relay/deploy.lock", transaction)
|
||||
self.assertIn('if self.request["mode"] == "update":', transaction)
|
||||
self.assertIn('self.host.install(self.attempt, self.request)', transaction)
|
||||
self.assertIn('raise Failure("recovery-source-mismatch")', transaction)
|
||||
self.assertIn('copy_path(path, snapshot / label)', transaction)
|
||||
self.assertIn('copy_path(snapshot / label, PATHS[label])', transaction)
|
||||
self.assertIn('estate_hash(PATHS) != self.receipt["snapshot_sha256"]', transaction)
|
||||
self.assertIn('WINDOW = 300', transaction)
|
||||
self.assertIn('self.watch("recovery", original_version, cursors)', transaction)
|
||||
self.assertIn('signal.signal(sig, signal.SIG_IGN)', transaction)
|
||||
self.assertIn('self.save("rolled_back")', transaction)
|
||||
self.assertIn('self.save("rollback_failed")', transaction)
|
||||
for required in ("alerts/events.db", "alerts/alert-history.json.imported",
|
||||
"alerts/alert-history.backup.json.imported", "ai_incidents.json", "snapshot_retained"):
|
||||
self.assertIn(required, transaction)
|
||||
self.assertNotIn('kill -QUIT', transaction + recovery + workflow)
|
||||
self.assertNotIn('eval ', transaction + recovery)
|
||||
self.assertNotIn("'--wait'", dispatcher)
|
||||
|
||||
self.assertIn('if [ "$#" -ne 16 ]', recovery)
|
||||
self.assertIn('SERVICE_NAME="pulse"', recovery)
|
||||
self.assertIn('RELAY_SERVICE_NAME="pulse-relay"', recovery)
|
||||
self.assertIn('EXPECTED_BINARY="/opt/pulse/bin/pulse"', recovery)
|
||||
self.assertIn('EXPECTED_UNIT="/etc/systemd/system/pulse.service"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_NODES "$MOCK_NODES"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_VMS_PER_NODE "$MOCK_VMS_PER_NODE"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_LXCS_PER_NODE "$MOCK_LXCS_PER_NODE"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_DOCKER_HOSTS "$MOCK_DOCKER_HOSTS"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_DOCKER_CONTAINERS "$MOCK_DOCKER_CONTAINERS"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_GENERIC_HOSTS "$MOCK_GENERIC_HOSTS"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_K8S_CLUSTERS "$MOCK_K8S_CLUSTERS"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_K8S_NODES "$MOCK_K8S_NODES"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_K8S_PODS "$MOCK_K8S_PODS"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_K8S_DEPLOYMENTS "$MOCK_K8S_DEPLOYMENTS"', recovery)
|
||||
self.assertIn("set_env_value PULSE_MOCK_SEED_METRICS_STORE false", recovery)
|
||||
self.assertIn('grep -Fxq "PULSE_MOCK_SEED_METRICS_STORE=false"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_TRENDS_SEED_DURATION "$MOCK_SEED_DURATION"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_TRENDS_SAMPLE_INTERVAL "$MOCK_SAMPLE_INTERVAL"', recovery)
|
||||
self.assertIn('set_env_value PULSE_MOCK_UPDATE_INTERVAL "$MOCK_UPDATE_INTERVAL"', recovery)
|
||||
self.assertIn('sudo systemctl restart "$SERVICE_NAME"', recovery)
|
||||
self.assertIn('sudo systemctl stop "$SERVICE_NAME"', recovery)
|
||||
self.assertIn('sudo kill -QUIT "$failed_pid"', recovery)
|
||||
self.assertIn("clear_demo_operational_history", recovery)
|
||||
self.assertIn("restore_demo_operational_history", recovery)
|
||||
self.assertIn("alerts/events.db", recovery)
|
||||
self.assertIn("alerts/alert-history.json.imported", recovery)
|
||||
self.assertIn("alerts/alert-history.backup.json.imported", recovery)
|
||||
self.assertIn("ai_incidents.json", recovery)
|
||||
self.assertIn("demo-operational-history.tar", recovery)
|
||||
self.assertNotIn('rm -f "/etc/pulse/', recovery)
|
||||
self.assertIn('AFTER_RELAY_PID" = "$BEFORE_RELAY_PID', recovery)
|
||||
self.assertIn('AFTER_BINARY_SHA" = "$BEFORE_BINARY_SHA', recovery)
|
||||
self.assertIn('AFTER_UNIT_SHA" = "$BEFORE_UNIT_SHA', recovery)
|
||||
self.assertIn('AFTER_DROPINS_SHA" = "$BEFORE_DROPINS_SHA', recovery)
|
||||
self.assertNotIn('AFTER_CONFIG_SHA" = "$BEFORE_CONFIG_SHA', recovery)
|
||||
self.assertIn("/etc/pulse/.env /etc/pulse/billing.json", recovery)
|
||||
self.assertIn("restore_runtime_config", recovery)
|
||||
self.assertIn("sudo cp --archive", recovery)
|
||||
self.assertNotIn("eval ", recovery)
|
||||
self.assertNotIn("sudo bash", recovery)
|
||||
|
||||
def test_blocked_record_tracks_current_target_and_candidate_version(self) -> None:
|
||||
blocked_record_surface = {
|
||||
|
||||
@@ -100,6 +100,21 @@ def _contract_reference(contract_path: str, needle: str, runtime_path: str) -> d
|
||||
|
||||
|
||||
class SubsystemLookupTest(unittest.TestCase):
|
||||
|
||||
def test_demo_transaction_sources_have_connected_proof_without_widening_release_metadata(self):
|
||||
for path in (".github/scripts/demo-runtime-transaction.py", ".github/scripts/dispatch-demo-runtime.py",
|
||||
".github/scripts/tests/demo_runtime_native.py", ".github/workflows/demo-runtime-native.yml"):
|
||||
with self.subTest(path=path):
|
||||
result = lookup_paths([path])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual({item["subsystem"] for item in result["impacted_subsystems"]}, {"deployment-installability"})
|
||||
requirement = result["files"][0]["matches"][0]["verification_requirement"]
|
||||
self.assertEqual(requirement["id"], "demo-runtime-transaction")
|
||||
self.assertEqual(sorted(requirement["exact_files"]), [
|
||||
".github/scripts/tests/test_demo_runtime_transaction.py",
|
||||
"scripts/installtests/demo_transaction_test.go",
|
||||
])
|
||||
|
||||
def git(self, repo_root: Path, *args: str) -> None:
|
||||
subprocess.run(
|
||||
["git", *args],
|
||||
|
||||
Reference in New Issue
Block a user