plugin-scanner 3.2.0__py3-none-any.whl → 3.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -99,6 +99,29 @@ def _report(discovery: Discovery, review: Review) -> dict[str, object]:
99
99
  def _readme(discovery: Discovery) -> str:
100
100
  metadata = discovery.metadata
101
101
  safe_name = re.sub(r"([\\`*_{}\[\]()#+.!|<>~-])", r"\\\1", metadata.name)
102
+ if metadata.kind == "cli":
103
+ verification = f"""The command source is `{command_source_path(metadata)}` and its portable fixture
104
+ is `{command_fixture_path(metadata)}`. Kit validation compiles the source and
105
+ runs these cases with Rust. CLI kits do not generate a Python detector or a
106
+ Python test module.
107
+
108
+ After integration, follow the [native validation sequence](https://github.com/hashgraph-online/hol-guard/blob/main/docs/guard/extension-builder/VALIDATION.md):
109
+ regenerate the complete program, rebuild the native compiler and runtime, and
110
+ run the fixture with a build envelope assembled from the destination checkout's
111
+ canonical sources. The kit's `base: "packaged"` envelope is for a new addition;
112
+ it cannot replace an extension already embedded in the rebuilt compiler.
113
+ """
114
+ else:
115
+ verification = f"""The MCP contribution is `{contribution_path(metadata)}`. Its generated Python
116
+ tests validate contribution metadata and native registration:
117
+
118
+ ```sh
119
+ python -m pytest {test_path(metadata)}
120
+ ```
121
+
122
+ Follow the [native validation sequence](https://github.com/hashgraph-online/hol-guard/blob/main/docs/guard/extension-builder/VALIDATION.md)
123
+ to regenerate and verify the complete catalog after integration.
124
+ """
102
125
  return f"""# {safe_name}: Guard contribution kit
103
126
 
104
127
  This is generated contributor knowledge, not a security certificate. The extension
@@ -108,7 +131,13 @@ validation never run the target or change Guard policy.
108
131
  ## Review first
109
132
 
110
133
  Read `report.json` and inspect every operation against the upstream implementation.
111
- Edit `review.json`, not the generated artifacts. Changed behavior needs
134
+ Copy the review file from this kit's parent directory:
135
+
136
+ ```sh
137
+ cp KIT/review.json REVIEW.json
138
+ ```
139
+
140
+ Edit `REVIEW.json`. Changed behavior needs
112
141
  `reviewed: true`, rationale, and an HTTPS evidence reference. Names, descriptions,
113
142
  help flags, and MCP annotations do not establish safety. Unknown CLI invocations
114
143
  retain review; unknown MCP tools inherit existing Guard handling.
@@ -116,21 +145,29 @@ retain review; unknown MCP tools inherit existing Guard handling.
116
145
  Recompile edits into a new directory from this kit's parent directory:
117
146
 
118
147
  ```sh
119
- hol-guard extensions generate --from snapshot --input KIT/discovery.json --review KIT/review.json --output REVIEWED_KIT
148
+ hol-guard extensions generate --from snapshot --input KIT/discovery.json --review REVIEW.json --output REVIEWED_KIT
120
149
  hol-guard extensions validate REVIEWED_KIT
121
150
  hol-guard extensions apply REVIEWED_KIT --repo /path/to/hol-guard
122
151
  ```
123
152
 
124
- Replace `KIT`, `REVIEWED_KIT`, and the checkout path with your actual paths.
125
- Inspect the plan, then explicitly add `--write` and optionally
126
- `--expected-plan PLAN_DIGEST`. Apply never commits, activates, or submits a PR.
153
+ Replace `KIT`, `REVIEW.json`, `REVIEWED_KIT`, and the checkout path with your actual paths.
154
+ Edit the copied review file before running snapshot generation. Inspect the plan,
155
+ then apply with `--expected-plan PLAN_DIGEST --write` using its printed digest.
156
+ Apply never commits, activates, or submits a PR.
127
157
  Existing manual edits are conflicts, not permission to overwrite work.
128
158
 
129
159
  ## Native verification in the destination checkout
130
160
 
161
+ Stage the shared review resources before running contribution tests:
162
+
131
163
  ```sh
132
164
  python scripts/release/stage_guard_cloud_review_artifacts.py
133
- python -m pytest {test_path(metadata)}
165
+ ```
166
+
167
+ {verification}
168
+ Run the shared contribution checks:
169
+
170
+ ```sh
134
171
  python -m pytest tests/test_guard_extension_contribution.py tests/test_guard_mcp_server_contribution.py
135
172
  ```
136
173
 
@@ -17,7 +17,9 @@ from .errors import BuilderError
17
17
  from .io import canonical_json, checked_path, parse_json, read_bytes
18
18
  from .models import Metadata
19
19
 
20
- LISTING_SCHEMA = "guard.extension-listing.v1"
20
+ LISTING_SCHEMA_V1 = "guard.extension-listing.v1"
21
+ LISTING_SCHEMA_V2 = "guard.extension-listing.v2"
22
+ LISTING_SCHEMA = LISTING_SCHEMA_V2
21
23
  MAX_LISTING_BYTES = 16_384
22
24
  MAX_TAGLINE_LENGTH = 140
23
25
  CATEGORY_LABELS = {
@@ -36,9 +38,15 @@ DEFAULT_LIMITATIONS = (
36
38
  )
37
39
 
38
40
 
39
- @lru_cache(maxsize=1)
40
- def listing_schema() -> dict[str, object]:
41
- payload = files("codex_plugin_scanner.guard.extension_builder").joinpath("listing.v1.schema.json")
41
+ @lru_cache(maxsize=2)
42
+ def listing_schema(schema_version: str = LISTING_SCHEMA) -> dict[str, object]:
43
+ filename = {
44
+ LISTING_SCHEMA_V1: "listing.v1.schema.json",
45
+ LISTING_SCHEMA_V2: "listing.v2.schema.json",
46
+ }.get(schema_version)
47
+ if filename is None:
48
+ raise BuilderError("listing_schema", "Listing uses an unsupported metadata schema version.")
49
+ payload = files("codex_plugin_scanner.guard.extension_builder").joinpath(filename)
42
50
  return cast(dict[str, object], json.loads(payload.read_text(encoding="utf-8")))
43
51
 
44
52
 
@@ -72,7 +80,10 @@ def _public_https(value: str) -> None:
72
80
  def validate_listing(payload: object, *, expected_id: str | None = None) -> dict[str, object]:
73
81
  """Validate bounded listing metadata without resolving links or performing a claim grant."""
74
82
 
75
- validator = Draft202012Validator(listing_schema(), format_checker=FormatChecker())
83
+ schema_version = payload.get("schemaVersion") if isinstance(payload, dict) else None
84
+ if not isinstance(schema_version, str) or schema_version not in {LISTING_SCHEMA_V1, LISTING_SCHEMA_V2}:
85
+ raise BuilderError("listing_schema", "Listing uses an unsupported metadata schema version.")
86
+ validator = Draft202012Validator(listing_schema(cast(str, schema_version)), format_checker=FormatChecker())
76
87
  try:
77
88
  validator.validate(payload)
78
89
  except (ValidationError, RecursionError) as exc:
@@ -80,7 +91,15 @@ def validate_listing(payload: object, *, expected_id: str | None = None) -> dict
80
91
  row = cast(dict[str, object], payload)
81
92
  if expected_id is not None and row["extensionId"] != expected_id:
82
93
  raise BuilderError("listing_identity", "Listing identity must match its native contribution and filename.")
83
- for value in [row["tagline"], *cast(list[str], row["limitations"])]:
94
+ text_values = [row["tagline"], *cast(list[str], row["limitations"])]
95
+ upstream: dict[str, object] | None = None
96
+ if schema_version == LISTING_SCHEMA_V2:
97
+ text_values.append(row["summary"])
98
+ raw_upstream = row["upstream"]
99
+ if raw_upstream is not None:
100
+ upstream = cast(dict[str, object], raw_upstream)
101
+ text_values.append(cast(str, cast(dict[str, object], upstream)["name"]))
102
+ for value in text_values:
84
103
  if (
85
104
  not isinstance(value, str)
86
105
  or value != value.strip()
@@ -90,6 +109,21 @@ def validate_listing(payload: object, *, expected_id: str | None = None) -> dict
90
109
  reference = row.get("documentationUrl")
91
110
  if isinstance(reference, str):
92
111
  _public_https(reference)
112
+ if schema_version == LISTING_SCHEMA_V2:
113
+ contributors = cast(list[dict[str, object]], row["contributors"])
114
+ if len({str(item["githubId"]) for item in contributors}) != len(contributors):
115
+ raise BuilderError("listing_contributors", "Contributor GitHub identities must be unique.")
116
+ for contributor in contributors:
117
+ roles = cast(list[str], contributor["roles"])
118
+ if len(set(roles)) != len(roles):
119
+ raise BuilderError("listing_contributors", "Contributor credit roles must be unique.")
120
+ references = cast(list[dict[str, object]], row["originalContributions"])
121
+ if len({str(item["url"]) for item in references}) != len(references):
122
+ raise BuilderError("listing_references", "Original contribution references must be unique.")
123
+ for item in references:
124
+ _public_https(cast(str, item["url"]))
125
+ if upstream is not None:
126
+ _public_https(cast(str, cast(dict[str, object], upstream)["url"]))
93
127
  if len(canonical_json(row).encode("utf-8")) > MAX_LISTING_BYTES:
94
128
  raise BuilderError("listing_limit", "Listing exceeds its byte budget.")
95
129
  return row
@@ -111,6 +145,10 @@ def listing_template(metadata: Metadata) -> str:
111
145
  "tagline": f"Reviewed operation coverage for {metadata.name}."[:MAX_TAGLINE_LENGTH].rstrip(),
112
146
  "category": "specialized-tools" if metadata.kind == "mcp" else "other",
113
147
  "limitations": list(DEFAULT_LIMITATIONS),
148
+ "summary": f"Reviewed operation coverage for {metadata.name} through the native Guard contract.",
149
+ "contributors": [],
150
+ "originalContributions": [],
151
+ "upstream": None,
114
152
  }
115
153
  try:
116
154
  _public_https(metadata.homepage)
@@ -0,0 +1,126 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://hol.org/guard/contracts/extension-listing.v2.schema.json",
4
+ "title": "HOL Guard extension contributor listing metadata",
5
+ "description": "Bounded public credit and provenance metadata. contributors is attribution only; maintainerGithubIds remains separately reviewed claim-authority input and validation does not grant authority.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schemaVersion",
10
+ "extensionId",
11
+ "tagline",
12
+ "category",
13
+ "limitations",
14
+ "summary",
15
+ "contributors",
16
+ "originalContributions",
17
+ "upstream"
18
+ ],
19
+ "properties": {
20
+ "schemaVersion": { "const": "guard.extension-listing.v2" },
21
+ "extensionId": {
22
+ "type": "string",
23
+ "maxLength": 256,
24
+ "pattern": "^(command|mcp)\\.[a-z0-9]+(?:[.-][a-z0-9]+)*$"
25
+ },
26
+ "tagline": { "type": "string", "minLength": 10, "maxLength": 140 },
27
+ "summary": { "type": "string", "minLength": 20, "maxLength": 2048 },
28
+ "category": {
29
+ "enum": [
30
+ "core-safety",
31
+ "cloud-infrastructure",
32
+ "data-resilience",
33
+ "delivery-remote",
34
+ "managed-services",
35
+ "package-supply-chain",
36
+ "specialized-tools",
37
+ "other"
38
+ ]
39
+ },
40
+ "limitations": {
41
+ "type": "array",
42
+ "minItems": 1,
43
+ "maxItems": 8,
44
+ "uniqueItems": true,
45
+ "items": { "type": "string", "minLength": 10, "maxLength": 400 }
46
+ },
47
+ "documentationUrl": {
48
+ "type": "string",
49
+ "minLength": 10,
50
+ "maxLength": 1024,
51
+ "pattern": "^https://",
52
+ "format": "uri"
53
+ },
54
+ "tags": {
55
+ "type": "array",
56
+ "maxItems": 8,
57
+ "uniqueItems": true,
58
+ "items": {
59
+ "type": "string",
60
+ "minLength": 2,
61
+ "maxLength": 30,
62
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
63
+ }
64
+ },
65
+ "maintainerGithubIds": {
66
+ "description": "Reviewed numeric GitHub IDs authorized to manage a publisher profile. Credits and pull-request authorship never grant this authority.",
67
+ "type": "array",
68
+ "maxItems": 8,
69
+ "uniqueItems": true,
70
+ "items": { "type": "string", "pattern": "^[1-9][0-9]{0,19}$" }
71
+ },
72
+ "contributors": {
73
+ "description": "Public credit only. These identities cannot authorize a claim.",
74
+ "type": "array",
75
+ "maxItems": 8,
76
+ "items": {
77
+ "type": "object",
78
+ "additionalProperties": false,
79
+ "required": ["githubId", "githubLogin", "roles"],
80
+ "properties": {
81
+ "githubId": { "type": "string", "pattern": "^[1-9][0-9]{0,19}$" },
82
+ "githubLogin": {
83
+ "type": "string",
84
+ "minLength": 1,
85
+ "maxLength": 100,
86
+ "pattern": "^[A-Za-z0-9](?:[A-Za-z0-9-]{0,98}[A-Za-z0-9])?$"
87
+ },
88
+ "roles": {
89
+ "type": "array",
90
+ "minItems": 1,
91
+ "maxItems": 3,
92
+ "uniqueItems": true,
93
+ "items": { "enum": ["author", "co-author", "reviewer", "maintainer"] }
94
+ }
95
+ }
96
+ }
97
+ },
98
+ "originalContributions": {
99
+ "type": "array",
100
+ "maxItems": 8,
101
+ "items": {
102
+ "type": "object",
103
+ "additionalProperties": false,
104
+ "required": ["kind", "url"],
105
+ "properties": {
106
+ "kind": { "enum": ["pull-request", "issue", "commit", "discussion"] },
107
+ "url": { "type": "string", "minLength": 10, "maxLength": 1024, "pattern": "^https://", "format": "uri" }
108
+ }
109
+ }
110
+ },
111
+ "upstream": {
112
+ "anyOf": [
113
+ { "type": "null" },
114
+ {
115
+ "type": "object",
116
+ "additionalProperties": false,
117
+ "required": ["name", "url"],
118
+ "properties": {
119
+ "name": { "type": "string", "minLength": 2, "maxLength": 160 },
120
+ "url": { "type": "string", "minLength": 10, "maxLength": 1024, "pattern": "^https://", "format": "uri" }
121
+ }
122
+ }
123
+ ]
124
+ }
125
+ }
126
+ }
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "3.2.0" # x-release-please-version
3
+ __version__ = "3.3.0" # x-release-please-version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows.
5
5
  Project-URL: Homepage, https://hol.org/guard
6
6
  Project-URL: Security, https://hol.org/guard/security
@@ -167,7 +167,7 @@ hol-guard command extensions command.git --json
167
167
 
168
168
  `command test` and `command explain` inspect the command without executing it or creating an approval. Use `hol-guard approvals` to resolve a pending request and `hol-guard receipts` to review the recorded decision.
169
169
 
170
- The [Extension directory](docs/guard/extensions/README.md) lists command coverage generated from the runtime registry. External contributions require explicit opt-in; required core protections remain enabled. To add coverage, follow the [Extension contribution guide](docs/guard/extensions/contributing.md).
170
+ The [Extension directory](docs/guard/extensions/README.md) lists command coverage generated from the Rust-compiled catalog. External contributions require explicit opt-in; required core protections remain enabled. To add coverage, follow the [Extension contribution guide](docs/guard/extensions/contributing.md).
171
171
 
172
172
  ### Check a package
173
173
 
@@ -424,6 +424,7 @@ The action may need approval under your active policy, or its tools or artifacts
424
424
  | [Policy specification](spec/guard-policy/v1alpha1/README.md) | GuardPolicy document format. |
425
425
  | [Policy recipes](docs/guard/policy-recipes.md) | Configuration examples for common workflows. |
426
426
  | [Extensions](docs/guard/extensions/README.md) | Built-in command rules and contribution guidance. |
427
+ | [Native extension authoring](docs/guard/extension-builder/README.md) | Canonical JSON sources, the Rust compiler, portable fixtures, and review kits. |
427
428
  | [Contribute an extension](#contribute-a-new-extension) | Generate, review, integrate, and test a new extension with the CLI. |
428
429
  | [Local vs. cloud](docs/guard/local-vs-cloud.md) | Local capabilities and optional cloud services. |
429
430
  | [Troubleshooting](docs/guard/troubleshooting.md) | Diagnosis and recovery. |
@@ -431,7 +432,17 @@ The action may need approval under your active policy, or its tools or artifacts
431
432
 
432
433
  ## Contribute a New Extension
433
434
 
434
- Use the **Extension Builder CLI** to turn exported command metadata or an MCP tool inventory into contribution files and tests. It works offline: it reads the export without importing or running the target tool.
435
+ Command extensions are authored as **declarative JSON compiled and evaluated by Rust**. Add metadata, permissions, matcher trees, and safe variants in `contributions/command-sources/command.<name>.json`, then verify behavior with portable JSON fixtures. Most extensions compose existing native operations; a new Rust operation is needed only when the existing matcher contracts cannot express the behavior.
436
+
437
+ | Contribution | Authoring input | Verification |
438
+ | :--- | :--- | :--- |
439
+ | Command coverage | `contributions/command-sources/command.<name>.json` | Portable fixtures evaluated by `guard-command-source test`. |
440
+ | MCP server knowledge | `contributions/mcp-servers/<id>.json` | MCP contribution tests and native catalog validation. |
441
+ | New matcher semantics | Reviewed Rust changes in `rust/crates/guard-command/` | Native contract, admission, evaluation, and regression tests. |
442
+
443
+ The Rust compiler generates command descriptors, the catalog, and the native matcher program. Python remains part of the CLI, build orchestration, and tests; new command coverage does not require a Python detector or registry registration. See the [authoring guide](docs/guard/extension-builder/README.md) for direct source authoring and the [architecture](docs/guard/command-extension-architecture.md) for the runtime boundary.
444
+
445
+ The **Extension Builder CLI** can create those command sources and portable fixtures from exported command metadata. It also supports MCP inventories. It works offline and reads the export without importing or running the target tool.
435
446
 
436
447
  **1. Propose the coverage.** Check the [Extension directory](docs/guard/extensions/README.md) for existing coverage. For a new capability, open an [Extension proposal](https://github.com/hashgraph-online/hol-guard/issues/new?template=command-extension-proposal.yml) with the proposed `command.<name>` ID, supported operations, destructive examples, safe counterparts, and upstream references. Extend an existing extension when it already owns the operation.
437
448
 
@@ -450,7 +461,7 @@ uv run --no-sync hol-guard extensions generate --from cli \
450
461
  uv run --no-sync hol-guard extensions validate samplectl-kit
451
462
  ```
452
463
 
453
- The output directory must be new, with an existing parent directory. The kit includes `discovery.json`, `review.json`, `report.json`, contribution metadata, a native detector, generated tests, and a file manifest.
464
+ The output directory must be new, with an existing parent directory. A command kit includes `discovery.json`, `review.json`, `report.json`, the canonical JSON source, a portable native fixture, a generated descriptor, and a file manifest. MCP kits contain their contribution metadata and generated Python tests.
454
465
 
455
466
  Other inputs: `--from help` reads saved command help; `--from click` reads a Click `Context.to_info_dict()` export; `--from oclif` reads `oclif.manifest.json`; `--from mcp` reads a complete exported `tools/list` result; and `--from snapshot` replays `discovery.json`. The `cli` example above uses normalized `guard.cli-surface.v1` JSON.
456
467
 
@@ -464,7 +475,7 @@ cp samplectl-kit/review.json samplectl-review.json
464
475
 
465
476
  Edit `samplectl-review.json`, keeping its discovery binding and operation IDs intact. CLI operations use `review` or `block`; the root operation stays `review`. Set `reviewed: true` for entries you have assessed, with rationale and a public HTTPS evidence reference. Add `safeArgv` only for exact, verified safe invocations. The [review format](docs/guard/extension-builder/README.md#review-and-recompile) includes a complete entry example.
466
477
 
467
- Recompile from the saved snapshot rather than editing generated detectors or manifests:
478
+ Recompile the saved snapshot after reviewing it:
468
479
 
469
480
  ```bash
470
481
  uv run --no-sync hol-guard extensions generate --from snapshot \
@@ -473,9 +484,12 @@ uv run --no-sync hol-guard extensions generate --from snapshot \
473
484
 
474
485
  uv run --no-sync hol-guard extensions validate samplectl-reviewed
475
486
  uv run --no-sync hol-guard extensions diff samplectl-kit samplectl-reviewed
487
+
488
+ "$HOL_GUARD_NATIVE_SOURCE_COMPILER" test \
489
+ < samplectl-reviewed/artifacts/tests/fixtures/command-source-samplectl.v1.json
476
490
  ```
477
491
 
478
- `diff` exits `0` for equal kits and `1` when valid kits differ. If the upstream export changes, generate and review a new snapshot.
492
+ `diff` exits `0` for equal kits and `1` when valid kits differ. The Rust fixture runner evaluates command text without executing it. If the upstream export changes, generate and review a new snapshot.
479
493
 
480
494
  **4. Preview and apply the integration.** On your contribution branch, preview the changes to the current checkout:
481
495
 
@@ -491,25 +505,27 @@ uv run --no-sync hol-guard extensions apply samplectl-reviewed --repo . \
491
505
  --write
492
506
  ```
493
507
 
494
- The write applies the reviewed plan to contribution files, the external trust map, catalog registration, packaging, and authoring ownership records. Existing IDs or conflicting files stop integration for review.
508
+ The write integrates the canonical source, fixture, generated contribution descriptor, external trust map, packaging, and authoring ownership records. Regenerate the complete program and catalog in the next step. Existing IDs or conflicting files stop integration for review.
495
509
 
496
- **5. Test and submit a pull request.** For the `samplectl` example:
510
+ **5. Test and submit a pull request.** Follow the [native validation sequence](docs/guard/extension-builder/VALIDATION.md) to regenerate the complete catalog, rebuild the compiler and runtime against that program, and run the contribution's fixtures against the integrated sources. This also covers updating an existing extension, where an addition to the packaged baseline would conflict with the existing ID. Then run the contribution checks and regenerate the public directory:
497
511
 
498
512
  ```bash
499
513
  uv run --no-sync python scripts/release/stage_guard_cloud_review_artifacts.py
500
- uv run --no-sync pytest -q tests/test_generated_cli_samplectl_extension.py
501
514
  uv run --no-sync pytest -q \
502
515
  tests/test_guard_extension_contribution.py \
503
516
  tests/test_guard_extension_trust.py \
517
+ tests/test_native_source_program.py \
504
518
  tests/test_guard_command_extension_registry.py
519
+ uv run --no-sync python scripts/export_extension_directory.py
520
+ uv run --no-sync python scripts/export_extension_directory.py --check
505
521
  uv run --no-sync python scripts/render_command_extension_directory.py
506
522
  uv run --no-sync python scripts/render_command_extension_directory.py --check
507
523
  git diff --check
508
524
  ```
509
525
 
510
- Use your generated test filename for a different slug. Add cases for destructive operations, safe previews, aliases, reordered flags, quoting, malformed input, and compound commands. Run lint and formatting checks on changed Python files. Inspect the final diff, commit the integration and regenerated directory, and open a PR against `main` linking the proposal and test results. Include the generated authoring records; keep scratch kit directories and raw upstream exports out of the PR.
526
+ Add fixture cases for destructive operations, safe previews, aliases, reordered flags, quoting, malformed input, and compound commands. Run the Rust checks when changing native semantics and the relevant Python checks when changing tooling. Inspect the final diff, commit the canonical inputs, generated projections, fixtures, and authoring records, and open a PR against `main` linking the proposal and test results. Keep scratch kit directories and raw upstream exports out of the PR.
511
527
 
512
- **Community contributions remain External and off by default.** Tests must prove they are inert until a local administrator enables them. Generating, applying, or merging a contribution does not activate it, and its detector cannot weaken Guard's required protections.
528
+ **Community contributions remain External and off by default.** Tests must prove they are inert until a local administrator enables them. Generating, applying, or merging a contribution does not activate it, and its rules cannot weaken Guard's required protections.
513
529
 
514
530
  [Full builder reference](docs/guard/extension-builder/README.md) · [Contribution review requirements](docs/guard/extensions/contributing.md) · [External extension contract](docs/guard/extension-contributions.md) · [Builder validation](docs/guard/extension-builder/VALIDATION.md)
515
531
 
@@ -517,15 +533,35 @@ Use your generated test filename for a different slug. Add cases for destructive
517
533
 
518
534
  ## Development
519
535
 
520
- Clone the repository and install the development dependencies with uv:
536
+ The development toolchain includes Python 3.10 or newer, [uv](https://docs.astral.sh/uv/), and Rust 1.88.0, pinned in [`rust/rust-toolchain.toml`](rust/rust-toolchain.toml). Rust builds the native runtime and extension compiler; Python supplies the CLI and development tooling. The commands below use a POSIX shell from the repository root. See [CONTRIBUTING.md](CONTRIBUTING.md) for Windows setup and the checks for each kind of change.
521
537
 
522
538
  ```bash
523
539
  git clone https://github.com/hashgraph-online/hol-guard.git
524
540
  cd hol-guard
525
- uv sync --extra dev
526
- uv run ruff check src tests
527
- uv run ruff format --check src tests
528
- uv run pytest --tb=short
541
+ uv sync --frozen --extra dev
542
+ rustup toolchain install 1.88.0 --profile minimal --component rustfmt --component clippy
543
+ cargo +1.88.0 build --locked --release --manifest-path rust/Cargo.toml \
544
+ -p guard-command --bin guard-command-source
545
+ cargo +1.88.0 build --locked --release --manifest-path rust/Cargo.toml \
546
+ -p hol-guard-runtime
547
+
548
+ export HOL_GUARD_NATIVE_SOURCE_COMPILER="$PWD/rust/target/release/guard-command-source"
549
+ export HOL_GUARD_NATIVE_TEST_SOURCE_COMPILER="$HOL_GUARD_NATIVE_SOURCE_COMPILER"
550
+ export HOL_GUARD_NATIVE_BINARY="$PWD/rust/target/release/hol-guard-runtime"
551
+
552
+ uv run --no-sync python scripts/build_native_command_program.py \
553
+ --compiler "$HOL_GUARD_NATIVE_SOURCE_COMPILER" --check
554
+ uv run --no-sync pytest tests/test_guard_extension_builder_public_docs.py \
555
+ tests/test_native_source_program.py --tb=short
556
+ ```
557
+
558
+ Those compiler overrides are for an editable checkout. Installed native wheels use their bundled compiler and verify its manifest. After changing canonical sources or Rust semantics, regenerate the projections and rebuild as described in the [validation guide](docs/guard/extension-builder/VALIDATION.md).
559
+
560
+ For Python tooling and package changes:
561
+
562
+ ```bash
563
+ uv run --no-sync ruff check src tests
564
+ uv run --no-sync ruff format --check src tests
529
565
  uv build
530
566
  ```
531
567
 
@@ -41,7 +41,7 @@ codex_plugin_scanner/trust_scoring.py,sha256=t_Lw13HZ766UCJzTtNNwllZK_k2ks_x-8St
41
41
  codex_plugin_scanner/trust_skill_scoring.py,sha256=e-SrMBgAruzFn4RD0pGpP9rtPXxc2ji_CKpcnFPRh3M,12542
42
42
  codex_plugin_scanner/trust_specs.py,sha256=aYGSB8M9RQp1uwhsRaWlVa1M9Vk51kUIxmBXkW8noZU,10729
43
43
  codex_plugin_scanner/verification.py,sha256=iVYDMyqjLQjD2KlnROTu4_sPLb_WyH8kFN-BOqR2kWM,33689
44
- codex_plugin_scanner/version.py,sha256=DsjWpRTUB61xDjBnsyO38Nt-JjvnJ5Y_9QXdsmWLPcQ,98
44
+ codex_plugin_scanner/version.py,sha256=uEdlQ680Q1mo3cw9jrleVlG3awmY6R3gi2Sk3ATSjYo,98
45
45
  codex_plugin_scanner/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  codex_plugin_scanner/checks/best_practices.py,sha256=uB3DXLggqxjfyBMH_1yvX4nyFhpIvaRHjTyyueoO-GQ,8473
47
47
  codex_plugin_scanner/checks/claude.py,sha256=DeKUbGPt2McSGhijzXLPL_SzjG_15WAB35_7mk8LU5A,10938
@@ -746,9 +746,10 @@ codex_plugin_scanner/guard/extension_builder/__init__.py,sha256=61jWiLq4RNyk8unD
746
746
  codex_plugin_scanner/guard/extension_builder/discover.py,sha256=BfBSKiA9ZreYaa0Vkqsc7EqPtk530eVqUG8QrMJpVds,2114
747
747
  codex_plugin_scanner/guard/extension_builder/errors.py,sha256=rJKUHDGfaXY1yeGsHuC6B9jN3Afzi1qGO0PDn6jiTRE,525
748
748
  codex_plugin_scanner/guard/extension_builder/io.py,sha256=iwIO_RmFeIxt0XYADLSiHL2XwtWrDEvSfAK_Q3A7gkE,5732
749
- codex_plugin_scanner/guard/extension_builder/kit.py,sha256=VS46Emv-kwvxCpTv7_BrEvFGXXSGiNpZwCZOO-Ab3qw,15078
750
- codex_plugin_scanner/guard/extension_builder/listing.py,sha256=MaqGOikyd3FUhwunibv3muYbxJ0-d0cjTU9SkM6V2yw,6629
749
+ codex_plugin_scanner/guard/extension_builder/kit.py,sha256=-vNBmONMBZG3PiaFqj6Z-PrSBH0U-XGqMxMP94Pyix0,16546
750
+ codex_plugin_scanner/guard/extension_builder/listing.py,sha256=Rfm6kLkGu9HJM89NvN1BO4JS7_FshO_OSZH9lJkmK20,8931
751
751
  codex_plugin_scanner/guard/extension_builder/listing.v1.schema.json,sha256=TEWEVboGa0JtcJoImDI0z-VfZ_WCUNwjBV8pDoz6oBg,2278
752
+ codex_plugin_scanner/guard/extension_builder/listing.v2.schema.json,sha256=87UMlr3UC4vbZv-wwhebVBBBachoSPelPOA8VLcajFk,3944
752
753
  codex_plugin_scanner/guard/extension_builder/listing_cli.py,sha256=CSFEtNcsT0TC-J4WYhbKJKT3mpX-fcBJB87EuQ63ldU,1102
753
754
  codex_plugin_scanner/guard/extension_builder/models.py,sha256=iGX7HyEcFq78MAqQO5Nj6ye5mqKHtwtWsqL5_iklzmE,9155
754
755
  codex_plugin_scanner/guard/extension_builder/native_source_compiler.py,sha256=f_VerXp0pdrMBjMx-aajix3y41M5tFgLQ4pU0eZXfkY,20196
@@ -1289,8 +1290,8 @@ codex_plugin_scanner/guard/contracts/data/guard-cloud-review/v2/contract.json,sh
1289
1290
  codex_plugin_scanner/guard/contracts/data/guard-cloud-review/v2/fixtures.json,sha256=vpf8NvLxmgI9ISG_mnSo5bBGYsegO4cZDwOIXmictfk,20769
1290
1291
  codex_plugin_scanner/guard/contracts/data/mcp_servers/contributions/mcp.filesystem.json,sha256=dgKScdJ07v8m_7S028oAKd_D0awf8tmKXWtdWWjtICc,1270
1291
1292
  codex_plugin_scanner/guard/contracts/data/mcp_servers/contributions/mcp.instapods.json,sha256=4pfklIwGN3vg3PHEW-aDr2Bql6sCv_oApQMmgk5SzlY,1449
1292
- plugin_scanner-3.2.0.dist-info/METADATA,sha256=GY6IoEuTblSSd1FwVMdWBi5tR7rlbvFbSLCE6J_WDfk,31060
1293
- plugin_scanner-3.2.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
1294
- plugin_scanner-3.2.0.dist-info/entry_points.txt,sha256=SLGKi3GvvSsPwave-k2JQt2meG0pM7aaC6VlUy47Crg,122
1295
- plugin_scanner-3.2.0.dist-info/licenses/LICENSE,sha256=UbiP0-niTtzc4d0UWk_KLc0SkRQH8AsG36b_YA-XM8E,11358
1296
- plugin_scanner-3.2.0.dist-info/RECORD,,
1293
+ plugin_scanner-3.3.0.dist-info/METADATA,sha256=RqE_b6mxky0mJ3YgcuqqBPEX6QkSfEfQCurAfbIeSEk,34909
1294
+ plugin_scanner-3.3.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
1295
+ plugin_scanner-3.3.0.dist-info/entry_points.txt,sha256=SLGKi3GvvSsPwave-k2JQt2meG0pM7aaC6VlUy47Crg,122
1296
+ plugin_scanner-3.3.0.dist-info/licenses/LICENSE,sha256=UbiP0-niTtzc4d0UWk_KLc0SkRQH8AsG36b_YA-XM8E,11358
1297
+ plugin_scanner-3.3.0.dist-info/RECORD,,