Skip to content

feat(iac): render portable GraphForge deployment specs - #251

Merged
DecisionNerd merged 2 commits into
mainfrom
feat/227-portable-deployment-spec
Jul 31, 2026
Merged

DecisionNerd merged 2 commits into
mainfrom
feat/227-portable-deployment-spec

Conversation

@DecisionNerd

@DecisionNerd DecisionNerd commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • define the closed graphforge-deployment-spec/1 contract and frozen production fixture
  • render the same canonical provider-neutral specification through Pulumi TypeScript, Pulumi Python, and Terraform
  • preserve caller ownership: no service build, provider resources, runtime checks, repository data, or dependency on extension: publish a queued GraphForge authority artifact #215
  • document the corrected ADR/IaC boundary and classify the shared contract for binding/IaC CI

Evidence

  • uv run --project iac/pulumi/python --extra test pytest iac/pulumi/python/tests (31 passed)
  • uv run --project iac/pulumi/python --extra test ruff check iac/pulumi/python
  • uv run --project iac/pulumi/python --extra test ruff format --check iac/pulumi/python
  • npm test && npm run format:check in iac/pulumi/typescript (13 passed)
  • iac/pulumi/tests/preview_acceptance.sh
  • TERRAFORM=<terraform-1.11.4> JQ=/usr/bin/jq iac/terraform/tests/deployment-spec-plan.sh (all six target topologies; 1,404-byte golden; 0 resources on apply/destroy)
  • uv run pytest tests/unit/test_graphforge_config_contract.py (3 passed)
  • scripts/ci/test-classify-changes.sh
  • make docs-build
  • git diff --check

Closes #227


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Note

Add portable GraphForge deployment spec rendering for Pulumi and Terraform

  • Adds a new graphforge-deployment-spec/1 contract with a JSON Schema, a golden example, and an ADR entry describing a runtime- and provider-agnostic deployment specification.
  • Implements renderDeploymentSpec/DeploymentSpec in TypeScript and Python Pulumi SDKs and a modules/deployment-spec Terraform module that produce a deterministic, secret-free projection from a resolved config, a target ID, and a validated artifact locator.
  • Validates artifact locators strictly: OCI images must be digest-pinned (repository@sha256:<64-hex>) with the digest matching the resolved config; non-OCI kinds must be credential-free HTTPS URLs; local paths, mutable tags, and inline credentials are rejected.
  • The Pulumi component (graphforge:deployment:DeploymentSpec) registers no provider children and stores no secrets in state; outputs are spec and canonical_json.
  • canonicalJson now escapes <, >, &, U+2028, U+2029 for Terraform compatibility, changing output for inputs containing those characters.
  • Risk: the resolved_config_sha256 computed in the Python validation module now uses the legacy-escaped canonical JSON, which can change the hash for configs containing <, >, &, U+2028, or U+2029.

Macroscope summarized 8984fae.

Summary by CodeRabbit

  • New Features

    • Added provider-neutral deployment specifications across Pulumi and Terraform.
    • Added canonical JSON output with artifact, target, topology, ownership, readiness, and capability details.
    • Added validation for immutable artifact locators and safe handling of credentials and secrets.
    • Deployment previews now expose and verify generated specifications.
  • Bug Fixes

    • Invalid locators, references, contracts, and configuration values are rejected or safely redacted.
  • Tests

    • Added comprehensive coverage for rendering, validation, previews, drift detection, and secret safety.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR adds a provider-neutral graphforge-deployment-spec/1 projection across Pulumi Python, Pulumi TypeScript, and Terraform. It validates immutable artifact locators, excludes sensitive and local data, registers no provider resources, and adds preview, contract, acceptance, and CI coverage.

Changes

Deployment specification

Layer / File(s) Summary
Pulumi Python deployment API
iac/pulumi/python/...
Adds artifact-locator validation, closed deployment projection rendering, canonical JSON serialization, and a state-only DeploymentSpec component.
Pulumi TypeScript deployment API
iac/pulumi/typescript/...
Adds deployment document types, fail-closed locator validation, canonical rendering, and a state-only DeploymentSpec component.
Terraform deployment-spec module
iac/terraform/modules/deployment-spec/*
Adds validated inputs, deployment projection locals, canonical JSON, artifact and target outputs, and contract preconditions.
Contract and renderer validation
iac/pulumi/*/test*, iac/terraform/tests/*, tests/unit/*
Adds deterministic rendering, golden compatibility, invalid-input, secret-exclusion, state-isolation, drift, destroy, and schema invariant tests.
Preview and CI integration
iac/pulumi/tests/preview/*, iac/pulumi/tests/verify_preview.py, scripts/ci/*
Previews export and verify deployment specifications. CI classification now triggers deployment-related checks for the deployment contract and fixture.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Preview
  participant DeploymentRenderer
  participant PulumiDeploymentSpec
  participant PreviewVerifier
  Preview->>DeploymentRenderer: Load resolved configuration and artifact locator
  DeploymentRenderer->>DeploymentRenderer: Validate target and immutable locator
  DeploymentRenderer-->>PulumiDeploymentSpec: Render deployment specification and canonical JSON
  PulumiDeploymentSpec->>Preview: Register state-only outputs
  Preview->>PreviewVerifier: Export deployment specification
  PreviewVerifier-->>PreviewVerifier: Verify allowed resource type and golden marker
Loading

Possibly related PRs

Suggested labels: core, ci-cd

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The code and tests address most issue requirements, but exact contract and fixture compliance cannot be verified because key files are path-filtered. Review the excluded schema docs/contracts/graphforge-deployment-spec-v1.schema.json (!/docs/) and production fixture (!/docs/, !/examples/) to confirm the closed contract and golden output.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed All summarized changes support issue #227 through deployment rendering, validation, tests, CI classification, or related configuration.
Title check ✅ Passed The title clearly and concisely describes the main change: rendering portable GraphForge deployment specifications for infrastructure as code.
Description check ✅ Passed The description explains the objectives, implementation scope, issue linkage, risks, and extensive validation evidence, despite omitting the repository template headings and checklists.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/227-portable-deployment-spec

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added testing Test coverage and testing infrastructure documentation Improvements or additions to documentation tooling Developer tooling and automation labels Jul 31, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (9)
iac/pulumi/python/src/graphforge_pulumi/deployment.py (3)

107-110: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Copy the ID lists into the projection.

The projection embeds the caller's list objects by reference. The TypeScript renderer copies them (index.ts lines 649-650). If a caller mutates resolved_config after rendering, the Python spec and the registered Pulumi output change too.

♻️ Proposed refactor
         "bindings": {
-            "secret_ids": target["secret_ids"],
-            "source_ids": target["source_ids"],
+            "secret_ids": list(target["secret_ids"]),
+            "source_ids": list(target["source_ids"]),
         },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iac/pulumi/python/src/graphforge_pulumi/deployment.py` around lines 107 -
110, Update the "bindings" projection in the deployment rendering flow to copy
target["secret_ids"] and target["source_ids"] into new list objects rather than
retaining caller-owned references. Preserve the existing values and output
structure while ensuring later mutations to resolved_config cannot alter the
generated spec or registered Pulumi output.

160-169: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Share one canonical serializer.

Lines 161-169 repeat the serialization options of render_deployment_spec_json. Two copies can drift, and drift breaks byte equivalence. Extract one private helper and call it from both places.

♻️ Proposed refactor
+def _canonical_text(spec: JsonObject) -> str:
+    return (
+        json.dumps(spec, ensure_ascii=False, separators=(",", ":"), sort_keys=True) + "\n"
+    )
+
+
 def render_deployment_spec_json(
     resolved_config: Mapping[str, Any],
     target_id: str,
     artifact_locator: str,
 ) -> str:
     """Return canonical UTF-8 JSON text with a single trailing newline."""
-    spec = render_deployment_spec(resolved_config, target_id, artifact_locator)
-    return (
-        json.dumps(
-            spec,
-            ensure_ascii=False,
-            separators=(",", ":"),
-            sort_keys=True,
-        )
-        + "\n"
-    )
+    return _canonical_text(render_deployment_spec(resolved_config, target_id, artifact_locator))
         spec = render_deployment_spec(resolved_config, target_id, artifact_locator)
-        canonical_json = (
-            json.dumps(
-                spec,
-                ensure_ascii=False,
-                separators=(",", ":"),
-                sort_keys=True,
-            )
-            + "\n"
-        )
+        canonical_json = _canonical_text(spec)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iac/pulumi/python/src/graphforge_pulumi/deployment.py` around lines 160 -
169, Extract the shared canonical JSON serialization logic from
render_deployment_spec and render_deployment_spec_json into one private helper,
preserving ensure_ascii=False, compact separators, sorted keys, and the trailing
newline. Update both callers to use that helper so their serialized output
remains byte-equivalent.

24-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Annotate _fail as NoReturn.

_fail always raises, but the annotation says -> None. Type checkers therefore assume execution continues after each _fail call. Two places then look unsafe: line 46 uses match.group() after the match is None branch, and line 58 reads parsed, which is bound only inside the try block. NoReturn removes both false positives and keeps runtime behavior identical.

♻️ Proposed refactor
-from typing import Any
+from typing import Any, NoReturn
-def _fail(message: str) -> None:
+def _fail(message: str) -> NoReturn:
     raise ValueError(f"invalid graphforge-deployment-spec/1: {message}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iac/pulumi/python/src/graphforge_pulumi/deployment.py` around lines 24 - 25,
The _fail function is annotated as -> None but always raises an exception, which
causes type checkers to incorrectly assume execution continues after calls to
_fail. Update the return type annotation of _fail from -> None to -> NoReturn
(imported from the typing module) to correctly signal that the function never
returns normally. This will eliminate false positives at line 46 and line 58
where type checkers incorrectly flag unreachable code.
iac/pulumi/typescript/src/index.ts (1)

535-559: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract one deployment-spec failure helper.

The prefix "invalid graphforge-deployment-spec/1: " is repeated in every throw site of this function. One helper removes the duplication and keeps the prefix stable, which matters because the tests assert on these messages.

♻️ Proposed refactor
+function failDeployment(message: string): never {
+  throw new Error(`invalid graphforge-deployment-spec/1: ${message}`);
+}
+
 function validateArtifactLocator(value: unknown, kind: string, expectedSha256: string): string {
   if (typeof value !== "string" || value.length < 1 || value.length > 2048) {
-    throw new Error(
-      "invalid graphforge-deployment-spec/1: artifactLocator must be a bounded string",
-    );
+    failDeployment("artifactLocator must be a bounded string");
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iac/pulumi/typescript/src/index.ts` around lines 535 - 559, In
validateArtifactLocator, extract a local failure helper that prepends the stable
"invalid graphforge-deployment-spec/1: " prefix to messages, then route each
existing throw through it while preserving the current message text and
validation behavior.
iac/pulumi/typescript/test/deployment-spec.test.ts (1)

36-43: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Sort canonical keys by code unit, not by locale.

canonical orders keys with localeCompare. The renderer's canonical JSON sorts by code unit. The two orders agree for the lowercase snake_case keys in this fixture, but they diverge for keys that differ in case or that contain _ next to letters. A future contract field could make this helper disagree with the renderer and produce a misleading failure.

♻️ Proposed comparator change
   return `{${Object.entries(value)
-    .sort(([left], [right]) => left.localeCompare(right))
+    .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
     .map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`)
     .join(",")}}`;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iac/pulumi/typescript/test/deployment-spec.test.ts` around lines 36 - 43,
Update the key comparator in canonical to use JavaScript’s code-unit ordering
rather than localeCompare, while preserving the existing recursive
canonicalization and output formatting.
tests/unit/test_graphforge_config_contract.py (1)

129-134: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a rejection case and the capability status assertion for the deployment example.

The test proves the deployment example validates, but it never proves the deployment schema rejects anything. Lines 85-90 already apply that pattern to the config and resolved schemas. The deployment block also omits the capability_compatibility status assertion that line 135 makes for infra.

♻️ Proposed additions
     assert deployment["readiness"] == {"status": "not_checked"}
     assert deployment["artifact"]["sha256"] in deployment["artifact"]["locator"]
+    assert deployment["capability_compatibility"]["status"] == "requirements_declared"
+    invalid_deployment = deepcopy(deployment)
+    invalid_deployment["infrastructure"]["status"] = "graphforge_owned"
+    assert not Draft202012Validator(deployment_schema, registry=registry).is_valid(
+        invalid_deployment
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/test_graphforge_config_contract.py` around lines 129 - 134, Add a
deployment-schema rejection assertion following the existing config and
resolved-schema pattern from lines 85-90, using the deployment example and an
invalid mutation to verify validation fails. In the deployment contract
assertions, add the expected capability_compatibility status assertion alongside
infrastructure, connectivity, readiness, and artifact checks.
iac/terraform/tests/deployment-spec-plan.sh (2)

109-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The Terraform negative suite cannot attribute a failure to a specific precondition. The loop treats any non-zero plan exit as success, and the fixture set covers five of the nine preconditions. Together these let a configuration error or a removed precondition keep the suite green.

  • iac/terraform/tests/deployment-spec-plan.sh#L109-L118: read an expected diagnostic per case and match it against the captured log before accepting the failure.
  • iac/terraform/tests/deployment-spec-invalid.json#L2-L43: add an expect field to every case, and add cases for the contract check, the single-match check, artifact_safe, and stable_source_ids && stable_secret_ids.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iac/terraform/tests/deployment-spec-plan.sh` around lines 109 - 118, The
Terraform negative suite must verify each case fails for its intended
precondition rather than accepting any non-zero plan. In
iac/terraform/tests/deployment-spec-plan.sh lines 109-118, read each case’s
expected diagnostic and require it to match the captured Terraform log before
accepting the failure. In iac/terraform/tests/deployment-spec-invalid.json lines
2-43, add an expect field to every existing case and add coverage for the
contract check, single-match check, artifact_safe, and stable_source_ids &&
stable_secret_ids preconditions.

40-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the redundant byte-length constant and normalize the key-order dependency.

The assertion on line 43 duplicates the comparison on line 42: the byte length 1404 is already implied by the JSON equality check. Terraform jsonencode sorts object keys lexicographically; jq tojson preserves the key order from the fixture file. The test passes only because the fixture is stored with sorted keys at every level. Document this coupling or normalize both sides to prevent the test from breaking if the fixture is reformatted. Removing the constant reduces maintenance burden.

♻️ Proposed fix
 "$JQ" -e --slurpfile expected \
   "$terraform_root/../../docs/contracts/examples/graphforge-deployment-spec-production-v1.json" '
-  (.planned_values.outputs.deployment_spec_json.value == (($expected[0] | tojson) + "\n")) and
-  ((.planned_values.outputs.deployment_spec_json.value | utf8bytelength) == 1404)
+  (.planned_values.outputs.deployment_spec_json.value
+     == (($expected[0] | to_entries | sort_by(.key) | from_entries | tojson) + "\n"))
 ' "$temporary_directory/plan.json" >/dev/null
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iac/terraform/tests/deployment-spec-plan.sh` around lines 40 - 44, Update the
deployment spec assertion in the jq expression to remove the redundant
utf8bytelength comparison and its hard-coded 1404 constant. Normalize the
Terraform output and expected fixture JSON before comparing, or explicitly
document the existing key-order coupling if normalization is not supported, so
fixture reformatting does not break the test.
iac/pulumi/python/tests/test_deployment.py (1)

173-185: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the bounded locator error message.

Use match="graphforge-deployment-spec/1" with pytest.raises for all non-OCI locator cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@iac/pulumi/python/tests/test_deployment.py` around lines 173 - 185, Update
test_non_oci_locator_rejects_mutable_or_sensitive_forms to pass
match="graphforge-deployment-spec/1" to pytest.raises, asserting the bounded
locator error message for every parameterized non-OCI locator case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@iac/pulumi/typescript/src/index.ts`:
- Around line 669-675: Update canonicalJson’s key comparator to use
deterministic code-point ordering instead of localeCompare, ensuring TypeScript
serialization matches Python json.dumps(sort_keys=True) across runtimes.
Preserve the existing recursive canonicalization behavior, and add coverage
using keys that differ by punctuation or case to lock the expected ordering.

In `@iac/terraform/modules/deployment-spec/main.tf`:
- Around line 89-95: Update the OCI branch of local.locator_safe to validate
local.artifact_sha before interpolating it into the regex, using the existing
digest-validation logic or symbol. Ensure invalid digests short-circuit to false
so regex() is never evaluated with untrusted metacharacters, preserving the
bounded deployment_spec precondition diagnostic.
- Around line 45-54: Update the stable_secret_ids validation to limit
length(local.secret_ids) to 128 instead of 256, matching the shared contract;
leave the stable_source_ids validation unchanged.
- Line 137: Update the resolved_config_sha256 computation in the deployment
specification module to hash a canonical JSON representation whose escaping
matches the TypeScript and Python renderers, rather than relying on Terraform
jsonencode’s extra escaping of <, >, &, U+2028, and U+2029. Apply the same
canonical escaping rule in every renderer and add regression fixtures covering
these characters so all implementations produce identical hashes.

In `@iac/terraform/tests/deployment-spec-plan.sh`:
- Around line 74-75: Update the state-resource assertion in
deployment-spec-plan.sh to recursively traverse values.root_module and its
child_modules, counting resources at every module level. Ensure the assertion
fails when any root or child module creates a resource, while still treating
missing resources or child_modules as empty collections.

---

Nitpick comments:
In `@iac/pulumi/python/src/graphforge_pulumi/deployment.py`:
- Around line 107-110: Update the "bindings" projection in the deployment
rendering flow to copy target["secret_ids"] and target["source_ids"] into new
list objects rather than retaining caller-owned references. Preserve the
existing values and output structure while ensuring later mutations to
resolved_config cannot alter the generated spec or registered Pulumi output.
- Around line 160-169: Extract the shared canonical JSON serialization logic
from render_deployment_spec and render_deployment_spec_json into one private
helper, preserving ensure_ascii=False, compact separators, sorted keys, and the
trailing newline. Update both callers to use that helper so their serialized
output remains byte-equivalent.
- Around line 24-25: The _fail function is annotated as -> None but always
raises an exception, which causes type checkers to incorrectly assume execution
continues after calls to _fail. Update the return type annotation of _fail from
-> None to -> NoReturn (imported from the typing module) to correctly signal
that the function never returns normally. This will eliminate false positives at
line 46 and line 58 where type checkers incorrectly flag unreachable code.

In `@iac/pulumi/python/tests/test_deployment.py`:
- Around line 173-185: Update
test_non_oci_locator_rejects_mutable_or_sensitive_forms to pass
match="graphforge-deployment-spec/1" to pytest.raises, asserting the bounded
locator error message for every parameterized non-OCI locator case.

In `@iac/pulumi/typescript/src/index.ts`:
- Around line 535-559: In validateArtifactLocator, extract a local failure
helper that prepends the stable "invalid graphforge-deployment-spec/1: " prefix
to messages, then route each existing throw through it while preserving the
current message text and validation behavior.

In `@iac/pulumi/typescript/test/deployment-spec.test.ts`:
- Around line 36-43: Update the key comparator in canonical to use JavaScript’s
code-unit ordering rather than localeCompare, while preserving the existing
recursive canonicalization and output formatting.

In `@iac/terraform/tests/deployment-spec-plan.sh`:
- Around line 109-118: The Terraform negative suite must verify each case fails
for its intended precondition rather than accepting any non-zero plan. In
iac/terraform/tests/deployment-spec-plan.sh lines 109-118, read each case’s
expected diagnostic and require it to match the captured Terraform log before
accepting the failure. In iac/terraform/tests/deployment-spec-invalid.json lines
2-43, add an expect field to every existing case and add coverage for the
contract check, single-match check, artifact_safe, and stable_source_ids &&
stable_secret_ids preconditions.
- Around line 40-44: Update the deployment spec assertion in the jq expression
to remove the redundant utf8bytelength comparison and its hard-coded 1404
constant. Normalize the Terraform output and expected fixture JSON before
comparing, or explicitly document the existing key-order coupling if
normalization is not supported, so fixture reformatting does not break the test.

In `@tests/unit/test_graphforge_config_contract.py`:
- Around line 129-134: Add a deployment-schema rejection assertion following the
existing config and resolved-schema pattern from lines 85-90, using the
deployment example and an invalid mutation to verify validation fails. In the
deployment contract assertions, add the expected capability_compatibility status
assertion alongside infrastructure, connectivity, readiness, and artifact
checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ceb0e5e5-b939-49ff-8bfa-654d1b585045

📥 Commits

Reviewing files that changed from the base of the PR and between 8b83368 and 755740b.

⛔ Files ignored due to path filters (13)
  • CHANGELOG.md is excluded by !**/*.md
  • docs/adr/0016-repository-integration-and-deployment-configuration.md is excluded by !**/*.md, !**/docs/**
  • docs/contracts/examples/graphforge-deployment-spec-production-v1.json is excluded by !**/docs/**, !**/examples/**
  • docs/contracts/graphforge-deployment-spec-v1.schema.json is excluded by !**/docs/**
  • docs/guides/infrastructure-validation.md is excluded by !**/*.md, !**/docs/**
  • docs/reference/changelog.md is excluded by !**/*.md, !**/docs/**
  • iac/pulumi/README.md is excluded by !**/*.md
  • iac/pulumi/python/README.md is excluded by !**/*.md
  • iac/pulumi/typescript/README.md is excluded by !**/*.md
  • iac/terraform/README.md is excluded by !**/*.md
  • iac/terraform/examples/deployment-spec/main.tf is excluded by !**/examples/**
  • iac/terraform/examples/deployment-spec/resolved.json is excluded by !**/examples/**
  • iac/terraform/modules/deployment-spec/README.md is excluded by !**/*.md
📒 Files selected for processing (20)
  • iac/pulumi/python/pyproject.toml
  • iac/pulumi/python/src/graphforge_pulumi/__init__.py
  • iac/pulumi/python/src/graphforge_pulumi/deployment.py
  • iac/pulumi/python/tests/test_deployment.py
  • iac/pulumi/tests/preview/python/__main__.py
  • iac/pulumi/tests/preview/typescript/index.js
  • iac/pulumi/tests/verify_preview.py
  • iac/pulumi/typescript/package.json
  • iac/pulumi/typescript/src/index.ts
  • iac/pulumi/typescript/test/deployment-spec.test.ts
  • iac/terraform/modules/deployment-spec/main.tf
  • iac/terraform/modules/deployment-spec/outputs.tf
  • iac/terraform/modules/deployment-spec/variables.tf
  • iac/terraform/modules/deployment-spec/versions.tf
  • iac/terraform/tests/deployment-spec-invalid.json
  • iac/terraform/tests/deployment-spec-plan.sh
  • iac/terraform/tests/plan.sh
  • scripts/ci/classify-changes.sh
  • scripts/ci/test-classify-changes.sh
  • tests/unit/test_graphforge_config_contract.py

Comment thread iac/pulumi/typescript/src/index.ts
Comment thread iac/terraform/modules/deployment-spec/main.tf
Comment thread iac/terraform/modules/deployment-spec/main.tf
Comment thread iac/terraform/modules/deployment-spec/main.tf
Comment thread iac/terraform/tests/deployment-spec-plan.sh Outdated
@DecisionNerd
DecisionNerd merged commit 5a835d1 into main Jul 31, 2026
20 checks passed
@DecisionNerd
DecisionNerd deleted the feat/227-portable-deployment-spec branch July 31, 2026 13:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation testing Test coverage and testing infrastructure tooling Developer tooling and automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(iac): render portable GraphForge core deployment specifications

1 participant