Skip to content

feat(compliance): add RMF/FedRAMP/DoD ATO package automation skill - #241

Open
ForeverYoung48 wants to merge 6 commits into
google:mainfrom
ForeverYoung48:feature/compliance-skill
Open

ForeverYoung48 wants to merge 6 commits into
google:mainfrom
ForeverYoung48:feature/compliance-skill

Conversation

@ForeverYoung48

@ForeverYoung48 ForeverYoung48 commented Sep 14, 2026

Copy link
Copy Markdown

Introduces .gemini/skills/compliance/, a self-contained agent skill that generates Authorization to Operate (ATO) packages from the Terraform in this repository. It extracts live architecture facts from a blueprint, hydrates authoritative templates, and emits the SSP, 20 policy manuals, SCTM, PPSM, HW/SW inventory, POA&M, FIPS 140-3 matrix, IR runbooks, NIST OSCAL packages and the master Path to Authorization roadmap as Markdown, Word, YAML and macro-enabled Excel.

Targets NIST SP 800-53 Rev. 5, FedRAMP Moderate/High, DoD CC SRG IL4/IL5/IL6, StateRAMP, CJIS and FISMA.

This is the first agent skill in the repository, so it also establishes the .gemini/skills/<skill-name>/ convention: each skill is defined by a SKILL.md with YAML frontmatter and resolves its own root at runtime rather than hardcoding paths or depending on a checkout location.

No Terraform, blueprint or GCP resource is changed by this commit. The skill is local, read-only tooling.

Adaptations for this repository

  • Retarget the system-name inference denylist from the source repository's layout to ours (workspace, stellar-engine, blueprints, modules, fast), so blueprints no longer infer a generic "Blueprints Platform" system name.
  • Register the skill in GEMINI.md: setup, the three-command operational workflow, target-folder isolation rules, and the python-hcl2 pin rationale.
  • Ignore **/.venv/ so the skill's isolated virtualenv stays out of the tree.

Correctness fixes to the extraction engine

  • Route parsed Terraform through the structured extraction path. The classifier branches on isinstance(body, dict), but the parsed AST was wrapped in HclBlock, a str subclass, so the gate never matched and every .tf file silently fell back to substring heuristics. That discarded CMEK key identity, reporting only that some key existed rather than which one, and dropped module-declared resources from the accreditation boundary, because the fallback early-returns on any name containing ${.

  • Resolve var.* references across the parsed AST. The structured path reads attributes directly and, unlike the text path's extract_hcl_attr, performed no interpolation, surfacing values such as ${var.vm_size} as machine types.

  • Resolve asset identifiers through one shared helper across all ten asset categories, so no name reaches a deliverable as raw expression syntax. Where a reference cannot be resolved statically, prefer the Terraform logical name over a stripped fragment such as "bucket", which is generic, collision-prone and indistinguishable from a real name.

  • Emit compute instance exposure as has_public_ip. The structured path used has_pub_ip, so the POA&M rule for internet-exposed instances, which tests has_public_ip is True, could never fire for anything ingested structurally, including via the recommended terraform show -json path.

  • Tolerate scalar protocol and ports firewall values. A single-element variable default such as [5432] is stored unwrapped, so ports = var.x arrives as an int; iterating it raised TypeError and aborted extraction for an entire blueprint rather than degrading on one field.

  • State an unresolvable CMEK reference in words instead of stripping ${var.kms_key_name} down to kms_key_name, which reads as a real key name in the SSP.

  • Make two HCL parser tests backend-aware. They encoded the in-repo fallback parser's behaviour and passed only when python-hcl2 was absent.

Verification

Measured across all 43 leaf blueprints: 43/43 extract with no failures and no HCL parse gaps; asset names containing unresolved expressions drop from 2 to 0 while the inventory retains all 52 asset items. Engine suite is 386/386, with 10 new regression tests covering CMEK key survival, boundary completeness for expression-named resources, expression-free identifiers, variable resolution, the POA&M field name and firewall shape tolerance. A full extract/generate/validate run against blueprints/il5/bigquery produces 71 schema-valid deliverables with 0 unresolved tokens.

Known limitation

Module-created infrastructure is not visible to static HCL scanning, so blueprints whose resources live behind module blocks report few or no assets. Driving the skill from terraform show -json output captures them, arriving through the same structured path fixed here.

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.

Fixes # (GitHub issue id)

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Deployment & Compliance Impact

  • Applicable Regimes:
    • US Region Restricted (e.g., Access Policy constraint)
    • FedRAMP Moderate
    • FedRAMP High
    • FedRAMP Moderate
    • DoD IL4
    • DoD IL5
    • General / All
  • NIST 800-53r5 Controls: (If this PR helps satisfy or modifies control implementations, list them here)

Checklist

Code Quality & Reusability

  • My code adheres to the Maximize Reusability principle. I have not redefined common elements and have reused existing base configurations and modules where possible.
  • [ x I have checked that no existing module or configuration in modules/ or fast/ can be leveraged for this change.
  • My code follows the established naming conventions outlined in documentation/naming-convention.md.

Documentation

  • I have updated the README.md of the modified module or blueprint.
  • I have added/updated documentation for inputs (variables) and outputs.

Security

  • My change adheres to GCP security best practices and the principle of least privilege.
  • I have ensured compliance with the targeted regime (FedRAMP Moderate, FedRAMP High, IL5, etc.).

Testing

  • I have tested my changes locally.
  • [] I have included details of my testing in this PR.

Testing Performed

No local testing performed

Introduces `.gemini/skills/compliance/`, a self-contained agent skill that
generates Authorization to Operate (ATO) packages from the Terraform in this
repository. It extracts live architecture facts from a blueprint, hydrates
authoritative templates, and emits the SSP, 20 policy manuals, SCTM, PPSM,
HW/SW inventory, POA&M, FIPS 140-3 matrix, IR runbooks, NIST OSCAL packages
and the master Path to Authorization roadmap as Markdown, Word, YAML and
macro-enabled Excel.

Targets NIST SP 800-53 Rev. 5, FedRAMP Moderate/High, DoD CC SRG IL4/IL5/IL6,
StateRAMP, CJIS and FISMA.

This is the first agent skill in the repository, so it also establishes the
`.gemini/skills/<skill-name>/` convention: each skill is defined by a SKILL.md
with YAML frontmatter and resolves its own root at runtime rather than
hardcoding paths or depending on a checkout location.

No Terraform, blueprint or GCP resource is changed by this commit. The skill
is local, read-only tooling.

Adaptations for this repository
-------------------------------

* Retarget the system-name inference denylist from the source repository's
  layout to ours (workspace, stellar-engine, blueprints, modules, fast), so
  blueprints no longer infer a generic "Blueprints Platform" system name.
* Register the skill in GEMINI.md: setup, the three-command operational
  workflow, target-folder isolation rules, and the python-hcl2 pin rationale.
* Ignore `**/.venv/` so the skill's isolated virtualenv stays out of the tree.

Correctness fixes to the extraction engine
------------------------------------------

* Route parsed Terraform through the structured extraction path. The
  classifier branches on `isinstance(body, dict)`, but the parsed AST was
  wrapped in HclBlock, a `str` subclass, so the gate never matched and every
  .tf file silently fell back to substring heuristics. That discarded CMEK key
  identity, reporting only that some key existed rather than which one, and
  dropped module-declared resources from the accreditation boundary, because
  the fallback early-returns on any name containing `${`.

* Resolve `var.*` references across the parsed AST. The structured path reads
  attributes directly and, unlike the text path's extract_hcl_attr, performed
  no interpolation, surfacing values such as `${var.vm_size}` as machine types.

* Resolve asset identifiers through one shared helper across all ten asset
  categories, so no name reaches a deliverable as raw expression syntax. Where
  a reference cannot be resolved statically, prefer the Terraform logical name
  over a stripped fragment such as "bucket", which is generic, collision-prone
  and indistinguishable from a real name.

* Emit compute instance exposure as `has_public_ip`. The structured path used
  `has_pub_ip`, so the POA&M rule for internet-exposed instances, which tests
  `has_public_ip is True`, could never fire for anything ingested structurally,
  including via the recommended `terraform show -json` path.

* Tolerate scalar `protocol` and `ports` firewall values. A single-element
  variable default such as `[5432]` is stored unwrapped, so `ports = var.x`
  arrives as an int; iterating it raised TypeError and aborted extraction for
  an entire blueprint rather than degrading on one field.

* State an unresolvable CMEK reference in words instead of stripping
  `${var.kms_key_name}` down to `kms_key_name`, which reads as a real key name
  in the SSP.

* Make two HCL parser tests backend-aware. They encoded the in-repo fallback
  parser's behaviour and passed only when python-hcl2 was absent.

Verification
------------

Measured across all 43 leaf blueprints: 43/43 extract with no failures and no
HCL parse gaps; asset names containing unresolved expressions drop from 2 to 0
while the inventory retains all 52 asset items. Engine suite is 386/386, with
10 new regression tests covering CMEK key survival, boundary completeness for
expression-named resources, expression-free identifiers, variable resolution,
the POA&M field name and firewall shape tolerance. A full
extract/generate/validate run against blueprints/il5/bigquery produces 71
schema-valid deliverables with 0 unresolved tokens.

Known limitation
----------------

Module-created infrastructure is not visible to static HCL scanning, so
blueprints whose resources live behind `module` blocks report few or no assets.
Driving the skill from `terraform show -json` output captures them, arriving
through the same structured path fixed here.
@Calvin-Cheng1
Calvin-Cheng1 self-requested a review September 14, 2026 15:26
Implements the outcome of a full review of the ATO automation skill.
The changes fall into five groups.

Truth in extraction (the central issue)

The extractor defaulted unstated security attributes to their compliant
value, so a blueprint that never mentioned a control was documented in
the generated SSP as enforcing it. Several of those defaults also
contradicted the fabric modules being invoked: modules/gcs defaults
versioning to null and modules/cloudsql-instance defaults
backup_configuration.enabled to false, yet both were reported as
enabled. KMS keys with no version_template were reported as HSM, which
fabricates a FIPS 140-3 Level 3 claim at IL5.

Attributes now resolve to the real provider or module default, or to an
explicit None when the degraded text-scan path cannot determine them. A
new DATA_GAP POA&M rule turns those unknowns into tracked findings, and
deliberately ignores explicit False values so a deficiency is never
double-reported under two identifiers. Against blueprints/il5/postgresql
this correctly surfaces an unenforced TLS posture that was previously
reported as compliant.

Safety of the automation

terraform plan is gated behind --allow-terraform-plan and runs with
-lock=false -refresh=false; syft and trivy behind --allow-scanners.
Semgrep defaults to the bundled offline ruleset, always passes
--metrics=off, and refuses cleartext HTTP rulesets. Dependency
bootstrapping is fail-closed via COMPLIANCE_ALLOW_BORROWED_DEPS.
Mock-detection branches were removed from production code in favour of
dependency injection. Binary writers gained boundary enforcement,
symlink refusal, zip-bomb guards, and atomic replace.

Correctness of generated artifacts

allowed_boundary is now passed into export_document rather than only
asserted afterwards; artifact enumeration is symlink-safe; --fix takes a
timestamped backup before regenerating.

Provenance and privacy

Stripped third-party Microsoft 365 tenant GUIDs from two eMASS
templates and documented origin, hashes, and modifications in
templates/PROVENANCE.md. Sanitized vendor names from shipped defaults.

Repository hygiene

Removed duplicate compliance_skill.md, corrected unverifiable test-count
and efficacy claims, added Apache headers, and added a CI job so the
engine suite actually runs (pytest.ini's testpaths never reached it).

Suite: 407 tests passing on Python 3.9, the declared floor.
Verified end to end on blueprints/il5/bigquery: 71 deliverables,
0 unresolved tokens, all schemas valid.
Removes all 489 emoji occurrences from the 38 files this PR adds, covering
console output, markdown documentation, and the policy, SSP, POA&M, PPSM,
HW/SW and FIPS templates that are hydrated into submitted ATO deliverables.

Three places had the emoji load-bearing rather than decorative:

- template_engine.py emitted badges as "<mark ...>WARNING [TYPE: label]</mark>".
  The bracketed marker already identifies the badge, so only the glyph was
  dropped. Tests asserting on those literals track the same change.
- Three tests asserted assertNotIn on a bare emoji. Stripping the literal in
  place would have left assertNotIn("") which passes against any input, so
  they were removed; each was paired with an assertNotIn("<mark") that already
  asserts the real property.
- validate_compliance_artifacts.py had a .replace() of the badge glyph, now a
  no-op and removed. docx_generator.py's callout classifier keys off text
  keywords, not glyphs, so only its titles and one regex prefix changed.

Deliberately left alone: the checkmark in Terraform variable tables under
fast/stages-aw/. That marker is emitted by tools/tfdoc.py, appears in 136
READMEs on main, and is regenerated by tooling, so changing it here would be
both inconsistent and transient.

Suite: 407 tests passing on Python 3.9. Verified by regenerating the full
package for blueprints/il5/bigquery and scanning all 73 deliverables,
including the OOXML inside .docx and .xlsm: zero emoji, and audit results
identical to before the change.
@aghassemlouei

aghassemlouei commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Ran an in-depth review and hardening pass across the compliance skill to get the PR ready for production and open source use. Here is a summary of the improvements and cleanups applied across the branch:

Accurate extraction

Previously, the extractor defaulted missing or unstated Terraform settings to compliant values (like assuming shielded VMs, SSL, backups, or HSM protection were on). Updated these to reflect genuine provider defaults, or explicit null values when static analysis cannot determine them. Also introduced a new DATA_GAP finding in .gemini/skills/compliance/src/compliance_engine/poam_rules.py so unknown configurations surface as tracked assessment items instead of false positives. CMEK detection was tightened to check real key references instead of matching substrings, and status tracking was aligned across poam_rules.py, semantic_linter.py, and generate_compliance_artifacts.py to prevent discrepancies across deliverables.

Operational safety

External tooling executions are now strictly controlled. Terraform plan no longer runs automatically on initialized workspaces; it is gated behind the --allow-terraform-plan flag, executes in an isolated temporary location with credential environment variables scrubbed, and uses non-locking, non-refreshing flags. Security scanners like Syft and Trivy are gated behind --allow-scanners to avoid unexpected remote database updates. Semgrep is configured to use the local bundled ruleset in .gemini/skills/compliance/config/semgrep_rules/public_sector_baseline.yaml with metrics turned off and cleartext HTTP URLs blocked. Also removed mock-checking logic from production code in favor of standard dependency injection, and updated the artifact validator so running with --fix creates a timestamped backup before touching existing files.

Security and file protections

All binary document exporters and hydrators now enforce path boundary checks directly within .gemini/skills/compliance/src/compliance_engine/export_strategies.py before writing to disk. Directory traversals reject symlinks during recursive walks, Excel template handling includes decompression bounds to guard against zip bombs, and formula injection defenses remain active. Additionally, third-party Microsoft 365 tenant GUIDs were removed from the Excel templates, and their origin and checksums are now documented in .gemini/skills/compliance/templates/PROVENANCE.md.

Open source readiness

Replaced hardcoded author strings with a configurable PREPARED_BY parameter that defaults to "Platform Security & Compliance Engineering Team" across all 20 policy documents, configuration files, docx_generator.py, and oscal_generator.py. Verified that no customer names or sensitive IDs remain. All emojis were removed from tests, templates, and docstrings, and HTML mark tags were replaced with clean text markers like [WARNING] and [INFORMATIONAL]. Also removed the redundant duplicate skill file, brought documented test numbers in line with reality, added Apache 2.0 headers across 56 files to satisfy tools/check_boilerplate.py, and added a test runner job in .github/workflows/ci.yml.

Code cleanup and optimization

Fixed missing imports (such as Callable in stig_resolver.py and typing helpers in test_hardening_scanner_edges.py), removed dead variables and unreachable assignment branches across extract_system_data.py and generate_compliance_artifacts.py, cleaned up unnecessary f-strings, and ensured public helpers like parse_yaml_scalar remain cleanly re-exported for backwards compatibility. Flake8 now passes with zero errors.

Verification

All 407 tests pass on Python 3.9 in under 50 seconds (with 2 skipped and 0 failures). An end-to-end run against blueprints/il5/bigquery successfully generated 71 schema-valid compliance deliverables with zero unresolved placeholders. The skill runs completely self-contained and is compatible with Antigravity as well as standard command line workflows.

@aghassemlouei aghassemlouei added enhancement New feature or request security Something is insecure or can be secured gemini for government Gemini for Government (G4G) related labels Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request gemini for government Gemini for Government (G4G) related security Something is insecure or can be secured

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants