Spaces:
Running
Running
Sync GitHub source 8ab9513367be0d2c0dcee1f38cfd7178aa71c7dd
Browse filesCanonical source: https://github.com/noqt/Lumi-Eggcracker/commit/8ab9513367be0d2c0dcee1f38cfd7178aa71c7dd
- HUGGINGFACE_MANIFEST.json +9 -9
- HUGGINGFACE_SYNC.json +3 -3
- README.md +15 -1
- index.html +2 -2
- src/lumi_eggcracker/cli.py +130 -1
- tests/test_cli.py +151 -0
HUGGINGFACE_MANIFEST.json
CHANGED
|
@@ -37,8 +37,8 @@
|
|
| 37 |
"size": 10537
|
| 38 |
},
|
| 39 |
"README.md": {
|
| 40 |
-
"sha256": "
|
| 41 |
-
"size":
|
| 42 |
},
|
| 43 |
"RELEASE_NOTES.md": {
|
| 44 |
"sha256": "64d330d0f297b15720fc65e6347ececc1b99a917a597d405ebfac04baf3222ea",
|
|
@@ -189,7 +189,7 @@
|
|
| 189 |
"size": 4101
|
| 190 |
},
|
| 191 |
"index.html": {
|
| 192 |
-
"sha256": "
|
| 193 |
"size": 22790
|
| 194 |
},
|
| 195 |
"integrations/prometheus/eggcracker.rules.yml": {
|
|
@@ -437,8 +437,8 @@
|
|
| 437 |
"size": 55591
|
| 438 |
},
|
| 439 |
"src/lumi_eggcracker/cli.py": {
|
| 440 |
-
"sha256": "
|
| 441 |
-
"size":
|
| 442 |
},
|
| 443 |
"src/lumi_eggcracker/client.py": {
|
| 444 |
"sha256": "0ac5dd4fdf564b2b7fd9e74de66d9ff083ac153864867b69fc078da9d66bbc66",
|
|
@@ -589,8 +589,8 @@
|
|
| 589 |
"size": 7176
|
| 590 |
},
|
| 591 |
"tests/test_cli.py": {
|
| 592 |
-
"sha256": "
|
| 593 |
-
"size":
|
| 594 |
},
|
| 595 |
"tests/test_collect_supported_path_receipt.py": {
|
| 596 |
"sha256": "79ae57bf3d78cac5fbe1b9d7db60462328f70cb17214bc75a5b5e7eff3ea0eef",
|
|
@@ -827,6 +827,6 @@
|
|
| 827 |
},
|
| 828 |
"schema": "noqt.huggingface_manifest.v1",
|
| 829 |
"source_repository": "https://github.com/noqt/Lumi-Eggcracker",
|
| 830 |
-
"source_revision": "
|
| 831 |
-
"source_url": "https://github.com/noqt/Lumi-Eggcracker/commit/
|
| 832 |
}
|
|
|
|
| 37 |
"size": 10537
|
| 38 |
},
|
| 39 |
"README.md": {
|
| 40 |
+
"sha256": "8d42000b36c3560d5e78054c94b9c547fe19214ad42bd1791837bb286a3370d4",
|
| 41 |
+
"size": 31503
|
| 42 |
},
|
| 43 |
"RELEASE_NOTES.md": {
|
| 44 |
"sha256": "64d330d0f297b15720fc65e6347ececc1b99a917a597d405ebfac04baf3222ea",
|
|
|
|
| 189 |
"size": 4101
|
| 190 |
},
|
| 191 |
"index.html": {
|
| 192 |
+
"sha256": "7e4f35f1f1b8e600fc69bf7da573dac5c23a6d74b20d55623fb0b5779e53bb18",
|
| 193 |
"size": 22790
|
| 194 |
},
|
| 195 |
"integrations/prometheus/eggcracker.rules.yml": {
|
|
|
|
| 437 |
"size": 55591
|
| 438 |
},
|
| 439 |
"src/lumi_eggcracker/cli.py": {
|
| 440 |
+
"sha256": "3be4ce117402ec750f9d86acdfe050e8dca16696f7450d19de7b51250e80e8ed",
|
| 441 |
+
"size": 15504
|
| 442 |
},
|
| 443 |
"src/lumi_eggcracker/client.py": {
|
| 444 |
"sha256": "0ac5dd4fdf564b2b7fd9e74de66d9ff083ac153864867b69fc078da9d66bbc66",
|
|
|
|
| 589 |
"size": 7176
|
| 590 |
},
|
| 591 |
"tests/test_cli.py": {
|
| 592 |
+
"sha256": "727d8d5f855c877320488c4064edbb0dc03e6f68b73ce472eb1803fe58089d2e",
|
| 593 |
+
"size": 18895
|
| 594 |
},
|
| 595 |
"tests/test_collect_supported_path_receipt.py": {
|
| 596 |
"sha256": "79ae57bf3d78cac5fbe1b9d7db60462328f70cb17214bc75a5b5e7eff3ea0eef",
|
|
|
|
| 827 |
},
|
| 828 |
"schema": "noqt.huggingface_manifest.v1",
|
| 829 |
"source_repository": "https://github.com/noqt/Lumi-Eggcracker",
|
| 830 |
+
"source_revision": "8ab9513367be0d2c0dcee1f38cfd7178aa71c7dd",
|
| 831 |
+
"source_url": "https://github.com/noqt/Lumi-Eggcracker/commit/8ab9513367be0d2c0dcee1f38cfd7178aa71c7dd"
|
| 832 |
}
|
HUGGINGFACE_SYNC.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"manifest": "HUGGINGFACE_MANIFEST.json",
|
| 3 |
-
"manifest_sha256": "
|
| 4 |
"mirrored_files": 191,
|
| 5 |
"mode": "DERIVED_READ_ONLY_MIRROR",
|
| 6 |
"release_reference": {
|
|
@@ -65,7 +65,7 @@
|
|
| 65 |
},
|
| 66 |
"schema": "noqt.huggingface_sync.v1",
|
| 67 |
"source_repository": "https://github.com/noqt/Lumi-Eggcracker",
|
| 68 |
-
"source_revision": "
|
| 69 |
-
"source_url": "https://github.com/noqt/Lumi-Eggcracker/commit/
|
| 70 |
"target": "https://huggingface.co/spaces/noqt/eggcracker"
|
| 71 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"manifest": "HUGGINGFACE_MANIFEST.json",
|
| 3 |
+
"manifest_sha256": "73af8a2e51b02f3016f7aff8ab7a04af7d918d474ef8a7a109389d8f9700af4a",
|
| 4 |
"mirrored_files": 191,
|
| 5 |
"mode": "DERIVED_READ_ONLY_MIRROR",
|
| 6 |
"release_reference": {
|
|
|
|
| 65 |
},
|
| 66 |
"schema": "noqt.huggingface_sync.v1",
|
| 67 |
"source_repository": "https://github.com/noqt/Lumi-Eggcracker",
|
| 68 |
+
"source_revision": "8ab9513367be0d2c0dcee1f38cfd7178aa71c7dd",
|
| 69 |
+
"source_url": "https://github.com/noqt/Lumi-Eggcracker/commit/8ab9513367be0d2c0dcee1f38cfd7178aa71c7dd",
|
| 70 |
"target": "https://huggingface.co/spaces/noqt/eggcracker"
|
| 71 |
}
|
README.md
CHANGED
|
@@ -11,7 +11,7 @@ short_description: Native Linux kill switch for supported local-AI workloads
|
|
| 11 |
---
|
| 12 |
|
| 13 |
> Official noqt Hugging Face distribution, generated from GitHub commit
|
| 14 |
-
> [`
|
| 15 |
> discovery and cloning; Eggcracker itself runs on a supported native Linux
|
| 16 |
> host, not on Hugging Face. A snapshot is called current only after the
|
| 17 |
> release-linked sync job verifies its returned Hub commit and full manifest.
|
|
@@ -547,6 +547,20 @@ exports only; it does not authenticate them or verify a live workload. See
|
|
| 547 |
[the export and comparison guide](docs/DETECTION_RECEIPT_EXPORT.md) for input,
|
| 548 |
output, redaction and filesystem behavior.
|
| 549 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 550 |
## Install and remove
|
| 551 |
|
| 552 |
The first-kill command is the recommended campaign path. A release is complete
|
|
|
|
| 11 |
---
|
| 12 |
|
| 13 |
> Official noqt Hugging Face distribution, generated from GitHub commit
|
| 14 |
+
> [`8ab9513367be`](https://github.com/noqt/Lumi-Eggcracker/commit/8ab9513367be0d2c0dcee1f38cfd7178aa71c7dd). This Space distributes the source for
|
| 15 |
> discovery and cloning; Eggcracker itself runs on a supported native Linux
|
| 16 |
> host, not on Hugging Face. A snapshot is called current only after the
|
| 17 |
> release-linked sync job verifies its returned Hub commit and full manifest.
|
|
|
|
| 547 |
[the export and comparison guide](docs/DETECTION_RECEIPT_EXPORT.md) for input,
|
| 548 |
output, redaction and filesystem behavior.
|
| 549 |
|
| 550 |
+
## Check installed health
|
| 551 |
+
|
| 552 |
+
For an installed source/build containing this change, record its version and
|
| 553 |
+
then request the bounded health snapshot:
|
| 554 |
+
|
| 555 |
+
```sh
|
| 556 |
+
eggcracker version
|
| 557 |
+
eggcracker doctor --summary
|
| 558 |
+
```
|
| 559 |
+
|
| 560 |
+
The snapshot is not containment proof. `doctor --summary` is available only in
|
| 561 |
+
the source/build that contains this change; its presence is not a claim that
|
| 562 |
+
the published v1.0.10 release includes this option.
|
| 563 |
+
|
| 564 |
## Install and remove
|
| 565 |
|
| 566 |
The first-kill command is the recommended campaign path. A release is complete
|
index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
<meta charset="utf-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 6 |
<meta name="description" content="Lumi Eggcracker is noqt's native Linux kill switch for unapproved supported local-AI workloads. Clone the complete source from Hugging Face.">
|
| 7 |
-
<meta name="noqt-source-revision" content="
|
| 8 |
<meta name="theme-color" content="#090a0c">
|
| 9 |
<title>Lumi Eggcracker — Native Linux AI kill switch</title>
|
| 10 |
<style>
|
|
@@ -649,7 +649,7 @@ sudo /usr/bin/python3 -I -S scripts/first_kill.py \
|
|
| 649 |
<section>
|
| 650 |
<div class="shell source-bar">
|
| 651 |
<div>
|
| 652 |
-
<div class="source-id">SOURCE COMMIT ·
|
| 653 |
<h2>Inspect every line.</h2>
|
| 654 |
<p>Complete source, tests, qualification documents and reproducible proof tooling are distributed in this repository.</p>
|
| 655 |
</div>
|
|
|
|
| 4 |
<meta charset="utf-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 6 |
<meta name="description" content="Lumi Eggcracker is noqt's native Linux kill switch for unapproved supported local-AI workloads. Clone the complete source from Hugging Face.">
|
| 7 |
+
<meta name="noqt-source-revision" content="8ab9513367be0d2c0dcee1f38cfd7178aa71c7dd">
|
| 8 |
<meta name="theme-color" content="#090a0c">
|
| 9 |
<title>Lumi Eggcracker — Native Linux AI kill switch</title>
|
| 10 |
<style>
|
|
|
|
| 649 |
<section>
|
| 650 |
<div class="shell source-bar">
|
| 651 |
<div>
|
| 652 |
+
<div class="source-id">SOURCE COMMIT · 8ab9513367be</div>
|
| 653 |
<h2>Inspect every line.</h2>
|
| 654 |
<p>Complete source, tests, qualification documents and reproducible proof tooling are distributed in this repository.</p>
|
| 655 |
</div>
|
src/lumi_eggcracker/cli.py
CHANGED
|
@@ -18,6 +18,122 @@ from .support_bundle import main as support_bundle_main
|
|
| 18 |
from .support_bundle import validate_main as validate_support_bundle_main
|
| 19 |
from .watchdog import main as watchdog_main
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
class _RejectDuplicateIdentifier(argparse.Action):
|
| 23 |
"""Accept one identifier option and fail closed on a repeated spelling."""
|
|
@@ -102,7 +218,12 @@ def _parser() -> argparse.ArgumentParser:
|
|
| 102 |
):
|
| 103 |
command = incident_commands.add_parser(action, help=help_text)
|
| 104 |
command.add_argument("incident_id")
|
| 105 |
-
commands.add_parser("doctor", help="check the installed protected supervisor")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
support = commands.add_parser(
|
| 107 |
"support-bundle", help="write a local redacted health and receipt bundle"
|
| 108 |
)
|
|
@@ -149,6 +270,14 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 149 |
return support_bundle_main(args.output)
|
| 150 |
try:
|
| 151 |
if args.command == "doctor":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
value = request("doctor")
|
| 153 |
print(json.dumps(value, sort_keys=True))
|
| 154 |
return 0 if value.get("result") == "PASS" else 6
|
|
|
|
| 18 |
from .support_bundle import validate_main as validate_support_bundle_main
|
| 19 |
from .watchdog import main as watchdog_main
|
| 20 |
|
| 21 |
+
_DOCTOR_SUMMARY_SCHEMA = "lumi-eggcracker.doctor-summary.v1"
|
| 22 |
+
_DOCTOR_SUMMARY_ERROR = "eggcracker: doctor summary unavailable"
|
| 23 |
+
_DOCTOR_SUMMARY_INSTALLATION_STATES = frozenset(
|
| 24 |
+
{"HEALTHY", "DRIFT", "RECOVERY_REQUIRED", "NOT_INSTALLED"}
|
| 25 |
+
)
|
| 26 |
+
_DOCTOR_SUMMARY_NETWORK_MODES = frozenset({"offline", "unsupported"})
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class _DoctorSummaryInvalid(ValueError):
|
| 30 |
+
"""The supervisor response cannot be safely reduced to a doctor summary."""
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def _doctor_summary(value: object) -> dict[str, object]:
|
| 34 |
+
"""Reduce a doctor response to a fixed, nonidentifying health object."""
|
| 35 |
+
|
| 36 |
+
if type(value) is not dict:
|
| 37 |
+
raise _DoctorSummaryInvalid
|
| 38 |
+
|
| 39 |
+
result = value.get("result")
|
| 40 |
+
if type(result) is not str or result not in {"PASS", "UNSUPPORTED"}:
|
| 41 |
+
raise _DoctorSummaryInvalid
|
| 42 |
+
|
| 43 |
+
def required_bool(container: object, key: str) -> bool:
|
| 44 |
+
if type(container) is not dict or key not in container:
|
| 45 |
+
raise _DoctorSummaryInvalid
|
| 46 |
+
item = container[key]
|
| 47 |
+
if type(item) is not bool:
|
| 48 |
+
raise _DoctorSummaryInvalid
|
| 49 |
+
return item
|
| 50 |
+
|
| 51 |
+
autonomous_discovery = required_bool(value, "autonomous_discovery")
|
| 52 |
+
cgroup_v2 = required_bool(value, "cgroup_v2")
|
| 53 |
+
pidfd = required_bool(value, "pidfd")
|
| 54 |
+
|
| 55 |
+
network = value.get("network")
|
| 56 |
+
if type(network) is not dict:
|
| 57 |
+
raise _DoctorSummaryInvalid
|
| 58 |
+
network_mode = network.get("mode")
|
| 59 |
+
if type(network_mode) is not str or network_mode not in _DOCTOR_SUMMARY_NETWORK_MODES:
|
| 60 |
+
raise _DoctorSummaryInvalid
|
| 61 |
+
network_primitives = network.get("primitives")
|
| 62 |
+
primitives_supported = required_bool(network_primitives, "supported")
|
| 63 |
+
network_cleanup = required_bool(network, "cleanup_healthy")
|
| 64 |
+
|
| 65 |
+
execution_boundary = value.get("execution_boundary")
|
| 66 |
+
execution_supported = required_bool(execution_boundary, "supported")
|
| 67 |
+
|
| 68 |
+
discovery = value.get("discovery")
|
| 69 |
+
discovery_healthy = required_bool(discovery, "healthy")
|
| 70 |
+
receipt_persistence = required_bool(discovery, "receipt_persistence_healthy")
|
| 71 |
+
|
| 72 |
+
incidents = value.get("incidents")
|
| 73 |
+
incidents_healthy = required_bool(incidents, "healthy")
|
| 74 |
+
incidents_lockdown = required_bool(incidents, "lockdown")
|
| 75 |
+
if not incidents_healthy and not incidents_lockdown:
|
| 76 |
+
raise _DoctorSummaryInvalid
|
| 77 |
+
|
| 78 |
+
installation = value.get("installation")
|
| 79 |
+
if type(installation) is not dict or "state" not in installation:
|
| 80 |
+
raise _DoctorSummaryInvalid
|
| 81 |
+
installation_state = installation["state"]
|
| 82 |
+
if (
|
| 83 |
+
type(installation_state) is not str
|
| 84 |
+
or installation_state not in _DOCTOR_SUMMARY_INSTALLATION_STATES
|
| 85 |
+
):
|
| 86 |
+
raise _DoctorSummaryInvalid
|
| 87 |
+
|
| 88 |
+
workload_identity = value.get("workload_identity")
|
| 89 |
+
workload_identity_healthy = required_bool(workload_identity, "healthy")
|
| 90 |
+
|
| 91 |
+
failed_checks: set[str] = set()
|
| 92 |
+
if not cgroup_v2:
|
| 93 |
+
failed_checks.add("cgroup_v2")
|
| 94 |
+
if not pidfd:
|
| 95 |
+
failed_checks.add("pidfd")
|
| 96 |
+
if network_mode != "offline":
|
| 97 |
+
failed_checks.add("network_mode")
|
| 98 |
+
if not primitives_supported:
|
| 99 |
+
failed_checks.add("network_primitives")
|
| 100 |
+
if not network_cleanup:
|
| 101 |
+
failed_checks.add("network_cleanup")
|
| 102 |
+
if not execution_supported:
|
| 103 |
+
failed_checks.add("execution_boundary")
|
| 104 |
+
if not discovery_healthy:
|
| 105 |
+
failed_checks.add("discovery")
|
| 106 |
+
if not receipt_persistence:
|
| 107 |
+
failed_checks.add("receipt_persistence")
|
| 108 |
+
if not incidents_healthy:
|
| 109 |
+
failed_checks.add("incidents")
|
| 110 |
+
if installation_state != "HEALTHY":
|
| 111 |
+
failed_checks.add("installation")
|
| 112 |
+
if not workload_identity_healthy:
|
| 113 |
+
failed_checks.add("workload_identity")
|
| 114 |
+
|
| 115 |
+
if result == "PASS":
|
| 116 |
+
if not autonomous_discovery or failed_checks:
|
| 117 |
+
raise _DoctorSummaryInvalid
|
| 118 |
+
summary_result = "READY"
|
| 119 |
+
else:
|
| 120 |
+
if autonomous_discovery:
|
| 121 |
+
raise _DoctorSummaryInvalid
|
| 122 |
+
if not failed_checks:
|
| 123 |
+
# The supervisor also gates readiness on quarantine_root, which is
|
| 124 |
+
# deliberately not exposed by its public doctor response.
|
| 125 |
+
failed_checks.add("supervisor_readiness")
|
| 126 |
+
summary_result = "NOT_READY"
|
| 127 |
+
|
| 128 |
+
return {
|
| 129 |
+
"failed_checks": sorted(failed_checks),
|
| 130 |
+
"next_action": (
|
| 131 |
+
"NONE" if summary_result == "READY" else "REVIEW_SUPERVISOR_READINESS"
|
| 132 |
+
),
|
| 133 |
+
"result": summary_result,
|
| 134 |
+
"schema": _DOCTOR_SUMMARY_SCHEMA,
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
|
| 138 |
class _RejectDuplicateIdentifier(argparse.Action):
|
| 139 |
"""Accept one identifier option and fail closed on a repeated spelling."""
|
|
|
|
| 218 |
):
|
| 219 |
command = incident_commands.add_parser(action, help=help_text)
|
| 220 |
command.add_argument("incident_id")
|
| 221 |
+
doctor = commands.add_parser("doctor", help="check the installed protected supervisor")
|
| 222 |
+
doctor.add_argument(
|
| 223 |
+
"--summary",
|
| 224 |
+
action="store_true",
|
| 225 |
+
help="emit a bounded readiness summary instead of the full doctor response",
|
| 226 |
+
)
|
| 227 |
support = commands.add_parser(
|
| 228 |
"support-bundle", help="write a local redacted health and receipt bundle"
|
| 229 |
)
|
|
|
|
| 270 |
return support_bundle_main(args.output)
|
| 271 |
try:
|
| 272 |
if args.command == "doctor":
|
| 273 |
+
if args.summary:
|
| 274 |
+
try:
|
| 275 |
+
summary = _doctor_summary(request("doctor"))
|
| 276 |
+
except Exception: # noqa: BLE001 - summary failures are intentionally constant
|
| 277 |
+
print(_DOCTOR_SUMMARY_ERROR, file=sys.stderr)
|
| 278 |
+
return 6
|
| 279 |
+
print(json.dumps(summary, sort_keys=True))
|
| 280 |
+
return 0 if summary["result"] == "READY" else 6
|
| 281 |
value = request("doctor")
|
| 282 |
print(json.dumps(value, sort_keys=True))
|
| 283 |
return 0 if value.get("result") == "PASS" else 6
|
tests/test_cli.py
CHANGED
|
@@ -11,6 +11,35 @@ from unittest.mock import patch
|
|
| 11 |
from lumi_eggcracker.cli import main
|
| 12 |
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
class CliTests(unittest.TestCase):
|
| 15 |
def test_version(self) -> None:
|
| 16 |
output = io.StringIO()
|
|
@@ -41,6 +70,128 @@ class CliTests(unittest.TestCase):
|
|
| 41 |
self.assertNotIn("_supervisor", help_text)
|
| 42 |
self.assertNotIn("network" + "-deny", help_text)
|
| 43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
def test_compare_detection_receipts_help_uses_installed_command(self) -> None:
|
| 45 |
output = io.StringIO()
|
| 46 |
with redirect_stdout(output), self.assertRaises(SystemExit) as raised:
|
|
|
|
| 11 |
from lumi_eggcracker.cli import main
|
| 12 |
|
| 13 |
|
| 14 |
+
def doctor_response(**overrides: object) -> dict[str, object]:
|
| 15 |
+
value: dict[str, object] = {
|
| 16 |
+
"autonomous_discovery": True,
|
| 17 |
+
"backend": "root-supervisor",
|
| 18 |
+
"cgroup_v2": True,
|
| 19 |
+
"catalogue": {"secret": "catalogue-canary"},
|
| 20 |
+
"discovery": {
|
| 21 |
+
"healthy": True,
|
| 22 |
+
"receipt_persistence_healthy": True,
|
| 23 |
+
"path": "/private/discovery-canary",
|
| 24 |
+
},
|
| 25 |
+
"execution_boundary": {"supported": True, "argv": ["argv-canary"]},
|
| 26 |
+
"incidents": {"healthy": True, "lockdown": False, "secret": "incident-canary"},
|
| 27 |
+
"installation": {"state": "HEALTHY", "path": "/private/install-canary"},
|
| 28 |
+
"network": {
|
| 29 |
+
"cleanup_healthy": True,
|
| 30 |
+
"mode": "offline",
|
| 31 |
+
"primitives": {"supported": True, "uid": "uid-canary"},
|
| 32 |
+
},
|
| 33 |
+
"pidfd": True,
|
| 34 |
+
"result": "PASS",
|
| 35 |
+
"version": "1.0.10",
|
| 36 |
+
"workload_identity": {"healthy": True, "uid": 4242},
|
| 37 |
+
"workload_uid": 4242,
|
| 38 |
+
}
|
| 39 |
+
value.update(overrides)
|
| 40 |
+
return value
|
| 41 |
+
|
| 42 |
+
|
| 43 |
class CliTests(unittest.TestCase):
|
| 44 |
def test_version(self) -> None:
|
| 45 |
output = io.StringIO()
|
|
|
|
| 70 |
self.assertNotIn("_supervisor", help_text)
|
| 71 |
self.assertNotIn("network" + "-deny", help_text)
|
| 72 |
|
| 73 |
+
def test_doctor_summary_ready_is_fixed_and_nonidentifying(self) -> None:
|
| 74 |
+
response = doctor_response()
|
| 75 |
+
output = io.StringIO()
|
| 76 |
+
error = io.StringIO()
|
| 77 |
+
with patch("lumi_eggcracker.cli.request", return_value=response) as request, redirect_stdout(output), redirect_stderr(error):
|
| 78 |
+
self.assertEqual(0, main(["doctor", "--summary"]))
|
| 79 |
+
self.assertEqual(
|
| 80 |
+
{
|
| 81 |
+
"failed_checks": [],
|
| 82 |
+
"next_action": "NONE",
|
| 83 |
+
"result": "READY",
|
| 84 |
+
"schema": "lumi-eggcracker.doctor-summary.v1",
|
| 85 |
+
},
|
| 86 |
+
json.loads(output.getvalue()),
|
| 87 |
+
)
|
| 88 |
+
self.assertEqual("", error.getvalue())
|
| 89 |
+
self.assertNotIn("canary", output.getvalue())
|
| 90 |
+
request.assert_called_once_with("doctor")
|
| 91 |
+
|
| 92 |
+
def test_doctor_summary_mixed_failures_are_sorted_and_deduplicated(self) -> None:
|
| 93 |
+
response = doctor_response(
|
| 94 |
+
autonomous_discovery=False,
|
| 95 |
+
cgroup_v2=False,
|
| 96 |
+
execution_boundary={"supported": False},
|
| 97 |
+
discovery={"healthy": False, "receipt_persistence_healthy": False},
|
| 98 |
+
incidents={"healthy": False, "lockdown": True},
|
| 99 |
+
installation={"state": "DRIFT"},
|
| 100 |
+
network={
|
| 101 |
+
"cleanup_healthy": False,
|
| 102 |
+
"mode": "unsupported",
|
| 103 |
+
"primitives": {"supported": False},
|
| 104 |
+
},
|
| 105 |
+
pidfd=False,
|
| 106 |
+
result="UNSUPPORTED",
|
| 107 |
+
workload_identity={"healthy": False},
|
| 108 |
+
)
|
| 109 |
+
output = io.StringIO()
|
| 110 |
+
with patch("lumi_eggcracker.cli.request", return_value=response), redirect_stdout(output):
|
| 111 |
+
self.assertEqual(6, main(["doctor", "--summary"]))
|
| 112 |
+
summary = json.loads(output.getvalue())
|
| 113 |
+
self.assertEqual(
|
| 114 |
+
[
|
| 115 |
+
"cgroup_v2",
|
| 116 |
+
"discovery",
|
| 117 |
+
"execution_boundary",
|
| 118 |
+
"incidents",
|
| 119 |
+
"installation",
|
| 120 |
+
"network_cleanup",
|
| 121 |
+
"network_mode",
|
| 122 |
+
"network_primitives",
|
| 123 |
+
"pidfd",
|
| 124 |
+
"receipt_persistence",
|
| 125 |
+
"workload_identity",
|
| 126 |
+
],
|
| 127 |
+
summary["failed_checks"],
|
| 128 |
+
)
|
| 129 |
+
self.assertEqual(len(summary["failed_checks"]), len(set(summary["failed_checks"])))
|
| 130 |
+
self.assertEqual("NOT_READY", summary["result"])
|
| 131 |
+
self.assertEqual("REVIEW_SUPERVISOR_READINESS", summary["next_action"])
|
| 132 |
+
self.assertEqual(
|
| 133 |
+
{"failed_checks", "next_action", "result", "schema"},
|
| 134 |
+
set(summary),
|
| 135 |
+
)
|
| 136 |
+
self.assertNotIn("canary", output.getvalue())
|
| 137 |
+
|
| 138 |
+
def test_doctor_summary_unsupported_without_visible_failure_is_honest(self) -> None:
|
| 139 |
+
response = doctor_response(autonomous_discovery=False, result="UNSUPPORTED")
|
| 140 |
+
output = io.StringIO()
|
| 141 |
+
with patch("lumi_eggcracker.cli.request", return_value=response), redirect_stdout(output):
|
| 142 |
+
self.assertEqual(6, main(["doctor", "--summary"]))
|
| 143 |
+
self.assertEqual(
|
| 144 |
+
{
|
| 145 |
+
"failed_checks": ["supervisor_readiness"],
|
| 146 |
+
"next_action": "REVIEW_SUPERVISOR_READINESS",
|
| 147 |
+
"result": "NOT_READY",
|
| 148 |
+
"schema": "lumi-eggcracker.doctor-summary.v1",
|
| 149 |
+
},
|
| 150 |
+
json.loads(output.getvalue()),
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
def test_doctor_summary_malformed_or_contradictory_response_is_constant_error(self) -> None:
|
| 154 |
+
malformed = [
|
| 155 |
+
{},
|
| 156 |
+
doctor_response(result=True),
|
| 157 |
+
doctor_response(cgroup_v2="true"),
|
| 158 |
+
doctor_response(network={"mode": "secret-path-canary"}),
|
| 159 |
+
doctor_response(autonomous_discovery=False),
|
| 160 |
+
doctor_response(autonomous_discovery=True, result="UNSUPPORTED"),
|
| 161 |
+
doctor_response(incidents={"healthy": False, "lockdown": False}),
|
| 162 |
+
doctor_response(installation={"state": "PRIVATE-CANARY"}),
|
| 163 |
+
]
|
| 164 |
+
for response in malformed:
|
| 165 |
+
with self.subTest(response=response):
|
| 166 |
+
output = io.StringIO()
|
| 167 |
+
error = io.StringIO()
|
| 168 |
+
with patch("lumi_eggcracker.cli.request", return_value=response), redirect_stdout(output), redirect_stderr(error):
|
| 169 |
+
self.assertEqual(6, main(["doctor", "--summary"]))
|
| 170 |
+
self.assertEqual("", output.getvalue())
|
| 171 |
+
self.assertEqual("eggcracker: doctor summary unavailable\n", error.getvalue())
|
| 172 |
+
self.assertNotIn("canary", error.getvalue())
|
| 173 |
+
|
| 174 |
+
output = io.StringIO()
|
| 175 |
+
error = io.StringIO()
|
| 176 |
+
with patch("lumi_eggcracker.cli.request", side_effect=OSError("/private/CANARY")), redirect_stdout(output), redirect_stderr(error):
|
| 177 |
+
self.assertEqual(6, main(["doctor", "--summary"]))
|
| 178 |
+
self.assertEqual("", output.getvalue())
|
| 179 |
+
self.assertEqual("eggcracker: doctor summary unavailable\n", error.getvalue())
|
| 180 |
+
self.assertNotIn("CANARY", error.getvalue())
|
| 181 |
+
|
| 182 |
+
def test_default_doctor_output_and_exit_remain_unchanged(self) -> None:
|
| 183 |
+
for result, expected_exit in (("PASS", 0), ("UNSUPPORTED", 6)):
|
| 184 |
+
with self.subTest(result=result):
|
| 185 |
+
response = doctor_response(
|
| 186 |
+
autonomous_discovery=result == "PASS", result=result
|
| 187 |
+
)
|
| 188 |
+
output = io.StringIO()
|
| 189 |
+
error = io.StringIO()
|
| 190 |
+
with patch("lumi_eggcracker.cli.request", return_value=response), redirect_stdout(output), redirect_stderr(error):
|
| 191 |
+
self.assertEqual(expected_exit, main(["doctor"]))
|
| 192 |
+
self.assertEqual(json.dumps(response, sort_keys=True) + "\n", output.getvalue())
|
| 193 |
+
self.assertEqual("", error.getvalue())
|
| 194 |
+
|
| 195 |
def test_compare_detection_receipts_help_uses_installed_command(self) -> None:
|
| 196 |
output = io.StringIO()
|
| 197 |
with redirect_stdout(output), self.assertRaises(SystemExit) as raised:
|