Skip to content

docs: document every attribute, add guides and gate docs in CI - #117

Merged
hllvc merged 23 commits into
mainfrom
fix/docs
Sep 15, 2026
Merged

hllvc merged 23 commits into
mainfrom
fix/docs

Conversation

@hllvc

@hllvc hllvc commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Rewrites the provider's documentation end to end: fixes pages that were factually wrong on the Registry, documents 226 previously undescribed attributes, adds nine guides where there were none, and adds CI gates so the docs cannot silently drift from the schemas again.

Motivation & Context

Customer feedback was that the docs are confusing and "blunt" — they don't explain what things do or show how resources are used. A sweep of every page, template, example and schema found three problems stacked on top of each other:

  • Some published pages are wrong. The policy resource page titles itself stackguardian_workflow_group; the policy data source titles itself stackguardian_role. Fourteen pages carry a wrong page_title, ten data sources are labelled "Resource", and four terraform import commands name a resource type that fails if copy-pasted.
  • The flagship examples do not work. The quickstart linked from the README as "a minimal working configuration" uses stackguardian_workflow, a resource type that no longer exists, so it fails at terraform plan.
  • The pages are almost entirely generated tables. 226 of 2001 attributes had no description and 22 rendered blank; 25 of 32 pages had no prose at all; there was no conceptual documentation of any kind — no object model, no auth setup, no import guide.

The root cause of the drift is that nothing checked it. make docs-validate verifies structure and frontmatter, not whether docs/ matches the current schemas.

Changes Made

Tooling and CI (Makefile, .github/workflows/test.yaml, tools/, scripts/)

  • Bump tfplugindocs v0.18.0 → v0.25.0. The pinned version cannot reproduce our own committed docs — it corrupts nested-schema headings, collapsing distinct blocks onto duplicate titles. v0.25.0 regenerates docs/ byte-identically from the current sources.
  • Add make docs-check, which regenerates and fails if docs/ differs. Wired into test.yaml.
  • Add make docs-validate-examples (scripts/validate-examples.sh): builds the provider, serves it from a local filesystem mirror, injects the terraform{}/provider{} blocks that doc fragments deliberately omit, and runs terraform validate on all 35 examples. No API calls, no credentials. Wired into test.yaml.
  • Pass --provider-name stackguardian to docs-validate; it previously worked only because CI checks out into a directory of that name.

Schema descriptions (internal/)

  • 226 undocumented attributes → 1. Most of the text already existed as a constant and had never been wired in: data-source schemas were written as bare Computed: true while their resource twins documented the same fields. Mirrored each data source from its twin, resolving ambiguous names by hand.
  • Added resource- and data-source-level summaries to the 20 schemas that had none.
  • Documented the platform's path-form IDs (/integrations/<name>, /secrets/<name>, /<org>/<name>:<rev>, and the :latest tag) on every attribute that takes one. iac_template_id previously gave no format at all despite accepting three forms.
  • Fixed descriptions that were wrong rather than thin: VCSTriggers pointed workflow_template users at a vcs_config attribute that resource does not have; RunnerConstraintsNames named an enum value that does not exist; several constants shipped typos and placeholder text to the Registry.
  • Marked stackguardian_role deprecated at the schema level so Terraform warns at plan time, and cleared it on rolev4, which inherits role's schema wholesale.

Page templates and guides (docs-templates/)

  • Added the two {{ .Description }} renders that tfplugindocs' default template has and ours had dropped, so schema-level descriptions reach the Registry for the first time.
  • Gave every page a domain subcategory — Access Control, Workflows, Templates, Infrastructure, Outputs — so the sidebar groups instead of listing 32 flat entries.
  • Corrected the wrong page titles, H1s and import commands described above.
  • Replaced hand-written HTML banners with schema-driven notices.
  • Added explanatory prose to the 25 pages that had none: nested workflow groups and adopt-on-collision, workflow_git's user-chosen id and trigger rollback, connector references, the container/revision relationship.
  • Added nine guides: Installation, Getting Started, Object Model, Resource IDs, Templates and Revisions, Access Control, Importing Existing Resources, Troubleshooting, Team Onboarding. The landing page now opens with a description and an index of them.

Examples and contributor docs (docs-examples/, docs-guides-assets/, root)

  • Rewrote the quickstart as a real deployment — workflow group, connector, workflow — with the connector wired in rather than hardcoded.
  • Gave all 17 data-source examples explanatory comments, where none had any, and removed hardcoded integration_id / iac_template_id literals so the connector-to-workflow and template-to-revision-to-workflow chains are demonstrated.
  • Fixed the onboarding projects: three different wrong provider sources, an internal QA endpoint, a quoted interpolation that silently produced a literal string, and an import script using API paths where the provider expects bare names.
  • Refreshed README.md, CHANGELOG.md, CODE_OF_CONDUCT.md, CLAUDE.md, TEST-SCENARIOS.md and both guide-asset READMEs, which pointed at directories that were never created.

Testing

  • go build ./... and go vet ./... clean.
  • make docs-validate passes.
  • make docs-check passes — docs/ regenerates byte-identically, verified by deleting the directory and regenerating from scratch.
  • make docs-validate-examples — 35/35 examples validate against the provider schema.
  • Each of the four commits verified independently against all gates, so the branch is bisectable.
  • Review the guide prose for product accuracy — several behaviours were derived from the code and the OpenAPI spec rather than confirmed by the team.

Risks & Edge Cases

  • No provider behaviour changes except one: stackguardian_role now carries a schema-level DeprecationMessage, so plans that use it emit a deprecation warning. No configuration breaks.
  • stack_template_revision.input_schemas.is_committed is the single attribute left undocumented — it is a bare *bool in the SDK with no semantics recorded anywhere, and a guess seemed worse than a gap.
  • Four defects found during this work are not addressed here and are deliberately left for a separate branch: the missing GitLab/Bitbucket/ADO webhook-ID attributes, workflow_git not unregistering webhooks when vcs_triggers is removed, runner_group_token not being marked Sensitive, and the provider logging the API key at DEBUG level.
  • docs-guides-assets/onboarding/project-test/ is untouched by request; it still references resource types that no longer exist and is excluded from the example harness.

Deployment Notes

  • Contributors need to reinstall the docs tool after pulling this: make tools-install. The older tfplugindocs will produce a corrupted diff against the regenerated docs.
  • Documentation is generated. Attribute text comes from MarkdownDescription in the schemas and page prose from docs-templates/; edit those and run make docs-generate. docs/ must never be edited by hand — CI now enforces this.

@hllvc hllvc self-assigned this Aug 31, 2026
@hllvc
hllvc marked this pull request as ready for review September 1, 2026 08:01
hllvc and others added 23 commits September 15, 2026 10:55
The pinned v0.18.0 cannot reproduce our own committed docs -- it corrupts
nested-schema headings, collapsing distinct blocks onto duplicate titles.
v0.25.0 regenerates docs/ byte-identically, so the pin was simply wrong.

Add `make docs-check`, which regenerates and fails if docs/ differs, and wire
it into CI. Without it a schema change silently leaves the published docs stale,
which is how they drifted in the first place.

Also pass --provider-name to docs-validate explicitly; it previously worked only
because CI checks out into a directory named terraform-provider-stackguardian.
Attribute text on the Registry comes from MarkdownDescription, and 226 of the
2001 documented attributes had none -- 22 more shipped an empty string. Most of
the missing text already existed as a constant and had simply never been wired
in: data-source schemas were written as bare `Computed: true` while their
resource twins documented the same fields.

Mirror each data source from its resource twin, and add the resource and
data-source level summaries that 20 of the 32 schemas were missing. Only one
attribute is left undocumented -- is_committed, whose meaning is not recorded
anywhere in the code or the SDK.

Document the path-form IDs the platform uses (/integrations/<name>,
/secrets/<name>, /<org>/<name>:<rev> and the :latest tag) on every attribute
that takes one; most previously gave no format at all. Fix descriptions that
were wrong rather than merely thin: VCSTriggers pointed workflow_template users
at a vcs_config attribute that resource does not have, RunnerConstraintsNames
named an enum value that does not exist, and several constants shipped typos and
placeholder text to the Registry.

Mark stackguardian_role deprecated at the schema level so Terraform warns at
plan time, and clear it on rolev4, which inherits role's schema wholesale.
The templates dropped the two `{{ .Description }}` renders that tfplugindocs'
own default template has, so every schema-level description was invisible on the
Registry -- the BETA notice on stack_template had not rendered for months. Add
both, and give every page a domain subcategory so the Registry sidebar groups
into Access Control, Workflows, Templates, Infrastructure and Outputs instead of
one flat list of 32 entries.

Fix titles that named the wrong resource. The policy resource page called itself
stackguardian_workflow_group and the policy data source called itself
stackguardian_role -- both live on the Registry today. Fourteen pages carried a
wrong page_title, ten data sources were labelled "Resource", and four import
commands named a resource type that would fail if copy-pasted.

Replace the hand-written HTML banners with schema-driven notices, and add
explanatory prose to the 25 pages that had none: nested workflow groups and the
adopt-on-collision behaviour, workflow_git's user-chosen id and trigger
rollback, how a connector is referenced, the container/revision relationship.

Add nine guides, where there were none: Installation, Getting Started, Object
Model, Resource IDs, Templates and Revisions, Access Control, Importing Existing
Resources, Troubleshooting and Team Onboarding. The provider landing page now
opens with a description and an index of them.
Add a validation harness -- scripts/validate-examples.sh, wired into CI as
`make docs-validate-examples`. It builds the provider, serves it from a local
filesystem mirror and runs `terraform validate` on every example. No API calls
and no credentials. It immediately found examples that could never have worked:
the workflow_template data source omitted its required id and set a Computed
attribute, workflow_template_revision omitted two required arguments, and the
workflow_group data source referenced an undeclared resource.

Rewrite the quickstart, which used stackguardian_workflow -- a resource type
that has not existed for a long time -- so the "minimal working configuration"
the README points at failed at plan. It now builds a real deployment:
workflow_group, connector, workflow_git, with the connector wired in rather
than hardcoded.

Give all 17 data-source examples explanatory comments, where none had any, and
show what you would look each one up for. Remove the hardcoded integration_id
and iac_template_id literals so the connector-to-workflow and
template-to-revision-to-workflow chains are demonstrated somewhere.

Fix the onboarding projects: three different wrong provider sources, an internal
QA endpoint, a quoted interpolation that silently produced a literal string, and
an import script that used API paths where the provider expects bare names and
referenced two resource types that do not exist.

Refresh the contributor docs. Both guide-asset READMEs pointed at directories
that were never created, CODE_OF_CONDUCT still had a placeholder contact,
CHANGELOG stopped at 0.1.0 with no pointer to releases, and CLAUDE.md described
a directory layout and a resource list that no longer match the code.
Every enum rendered as a bare list of backend tokens -- "Options: FORM_JSONSCHEMA,
RAW_HCL, RAW_JSON, NONE" -- with nothing saying what any of them does. The API
spec cannot help here: 39 of its 47 enum descriptions are tautological, of the
form "GITHUB_COM - GITHUB_COM".

Gloss each value instead: what the input schema types mean, what each policy
action does on pass and on fail, which cloud and VCS provider each connector
kind targets, and where PLAIN_TEXT and SECRET_VALUE differ. Link out to
docs.stackguardian.io per connector kind where a page exists.

Document policy_type, which was previously just `"GENERAL" or "FILTER.INSIGHT"`.
GENERAL is the enforcement policy; FILTER.INSIGHT filters findings out of the
Insight dashboard and takes neither scope nor approval settings -- which matches
the API, where PolicyFilterInsight has no EnforcedOn, Approvers or Tags.

Two fixes this surfaced:

- Attribute descriptions render inline inside a Markdown list item, so a literal
  newline escapes the attribute list and breaks the page. Two descriptions added
  earlier in this branch did that; both now use the inline <ul><li> style the
  rest of the schema uses.
- wf_type inside stack_template_revision listed three values while the workflow
  resources list seven. Stacks mix workflow types, so the narrow list was wrong.

Also correct the policy page prose, which still claimed enforced_on takes the
same paths as a role's allowed_permissions. It does not -- roles take bare
resource names.
Glossing the step template values turned up documented values that do not
exist. Checked every enum in the docs against the API spec and the SDK:

- Environment variable `kind` was documented as PLAIN_TEXT or SECRET_VALUE.
  The real enum is PLAIN_TEXT or VAULT_SECRET (EnvVarsKindEnum in the spec, and
  EnvVarsKindEnumVaultSecret in the SDK). SECRET_VALUE has never existed, so
  anyone following the docs to reference a secret got a value the API rejects.
  It was the most repeated enum token in the docs, 92 occurrences. `secret_id`
  named a third value, SECRET_REF, which does not exist either. No test covers
  the secret path, which is why this survived.
- workflow_step_template `source_config_kind` listed DOCKER_IMAGE, GIT_REPO, S3
  and `source_config_dest_kind` listed CONTAINER_REGISTRY, GIT, S3. GIT_REPO, S3
  and GIT appear nowhere in the spec; both fields are single-valued.
- `wf_type` listed the seven template kinds. WfTypeEnum is TERRAFORM, OPENTOFU,
  CUSTOM, and it backs every wf_type field. A Helm or Ansible template runs as a
  CUSTOM workflow. This also reverts a change earlier in this branch that
  widened the correct three-value list inside stack_template_revision.

`template_type` is now explained as the discriminator across all four template
families -- WORKFLOW_STEP, IAC, IAC_GROUP, IAC_POLICY map to step, workflow,
stack and policy templates -- and noted as read-only, since it is Computed.

Every enum value now rendered in the docs is present in the API spec.

Two step-template constants also embedded literal newlines, which break the
attribute list; both are now inline.
Four more places were still showing bare tokens:

- Stack template `source_config_kind` listed eight values. The API is explicit
  here: it is always `MIXED` for a stack, because a stack groups workflows built
  from different tools and the tool for each one is recorded on that workflow.
  The other values belong on a workflow template.
- `template_type` on the step template revision used a second constant that the
  earlier pass missed, so it still showed the four raw values.
- `vcs_triggers.type` on a workflow template listed three values and ended in a
  dangling comma.
- `vcs_triggers` on workflow_git explained its prerequisites in terms of raw
  values; it now names them and links to the VCS connector docs.

Also promote the `terraform_version` description that was stranded inline in one
data source to the shared constant, so all six users of the field explain the
engine prefix rather than saying "Terraform version to use."

Every enum value in the docs is present in the API spec, and the only remaining
bare list is ENABLED/DISABLED on a schedule, which needs no gloss.
The API stopped accepting 1.6.0 (fixed on main in #119, merged here); align the
example configs and the Templates guide from 1.5.0 to 1.5.7, the version the
test suite now validates against, so copied examples use a known-good value.
- Updated subcategories for data sources and resources to better reflect their purposes, changing "Access Control" to "Access Management" and "Infrastructure" to "Connectors" where applicable.
- Added a new guide on "Access Management" detailing roles and role assignments.
- Created a new guide on "Policies" explaining their purpose and usage in workflow runs.
- Enhanced descriptions and examples in the policy documentation to clarify the policy body sources and their configurations.
- Improved the clarity of output descriptions for various resources, particularly around approvers and schema types.
- Updated links in the "Getting Started" and "Installation" guides to point to the new "Access Management" guide.
- Adjusted the "Object Model" and "Troubleshooting" guides to reflect the updated terminology and concepts.
…feature requests

- Created a bug report template to streamline issue reporting for provider bugs.
- Added a documentation issue template to facilitate feedback on documentation clarity and completeness.
- Introduced a feature request template to gather suggestions for new resources and enhancements.

chore: disable blank issues and add contact links in config.yml

- Disabled blank issues to redirect users to the template chooser.
- Added links to provider documentation, troubleshooting guide, and feedback discussion for better user support.

chore: implement a pull request template for consistent contributions

- Added a pull request template to ensure contributors provide necessary information and follow best practices.

chore: inject a revamp banner into documentation pages

- Added a script to inject a banner indicating that documentation is being revamped, ensuring users are aware of ongoing changes.
- Updated multiple resource and data source documentation files to include the revamp banner for clarity.
- Updated README.md for onboarding to clarify roles, workflows, and permissions.
- Modified import.sh to reflect new resource naming conventions and added workflow import.
- Revised project-01.tf to implement stackguardian_rolev4 roles and improve permission management.
- Enhanced project-02.tf to define hierarchical team roles with distinct permissions for managers and developers.
- Updated TeamOnboarding.md to include new policy examples and clarify the structure of onboarding configurations.
- Updated the Makefile to clarify the purpose of the docs-validate-examples target.
- Revised comments in policy resource examples to specify that approvers can be email addresses or SSO group names.
- Modified Policies.md and ResourceIDs.md to reflect changes in the format of approvers and resource IDs.
- Added a new script (extract-doc-blocks.py) to extract and validate Terraform blocks from documentation prose.
- Enhanced validate-examples.sh to validate Terraform blocks embedded in documentation, ensuring they are type-checked correctly.
- Updated various documentation files to use the new template ID format and improved clarity on approver specifications.
The docs step was last in the job, so a job that stopped at the first
failing step never reached it. That made documentation validation
conditional on the production API being reachable: an unrelated
acceptance-test failure, an unavailable secret, or an API hiccup took the
docs checks with it, and a fork PR without secret access got no signal at
all.

Nothing in that step needs credentials or a network -- the provider is
served from a local filesystem mirror -- and it finishes in a couple of
minutes against the suite's fifteen, so it now runs first and fails fast.

Within the step, docs-validate-examples moves ahead of docs-check for the
same reason: docs-check regenerates docs/ and, under set -eu, a stale
tree would have stopped the run before the examples were type-checked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Registry navigation sorts alphabetically within a subcategory and offers
no ordering control, so grouping is the only lever. Stack pages were
split across Templates and Workflows, which put two stack_* data sources
at the head of a list headed "Workflows". They now sit in Stacks, and
workflow groups get their own subcategory, leaving Workflows as the
workflow-execution pages and Templates symmetric at four templates by
resource and data source.

The workflow_git example was three thin snippets that declared no
workflow group and set wf_type = CUSTOM against a public repo. It is now
three progressive ones -- minimal, nested group with inputs, and a
production workflow with a cloud connector, private repo, drift
detection, an approval gate, VCS triggers and notifications. Each
declares its own group and references it, so the dependency and the
creation order are visible. Attribute names and nesting modes were taken
from the provider schema rather than written from memory; three would
have been wrong by intuition, since mini_steps email events are lists and
vcs_triggers.push is a map keyed on createWfRun.

Alongside that, three documentation constants:

  - SecretReferenceSyntax, new and shared, describing the
    ${secret::<name>} form. The separator is a double colon; the
    single-dot spelling that appears in some tooling resolves nothing.
    Confirmed against live workflows, where the double-colon form is in
    use and the dotted one matches nothing.
  - EnvVarConfigTextValue was stale: it carried raw HTML styling and
    referred to a kind called TEXT, which does not exist. Rewritten
    around PLAIN_TEXT with the state-exposure warning.
  - WorkflowIacInputDataSchemaType now notes that the platform returns
    NO_CODE_JSON on existing workflows. It is absent from the SDK enum,
    so it is described as passed through rather than offered as a value
    to write.

The accompanying tests pin these descriptions to the SDK. Three enums
overlap without being interchangeable -- RAW_HCL is an IaC-input value
but not a policy one, TIRITH_JSON the reverse -- so a value documented
against the wrong enum points readers at something the attribute
rejects. Referencing the SDK constants directly means an upstream rename
breaks compilation rather than an assertion. One test fails deliberately
if the SDK starts accepting NO_CODE_JSON, so the caveat gets promoted
rather than quietly outliving its reason.

docs/ is generated from all three of these inputs, so they land together:
splitting them would leave intermediate commits whose generated output
did not match its sources, and docs-check would fail on each.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Updated various test files to replace hardcoded resource names with acctest.ResourceName for better uniqueness and consistency across tests.
- This change applies to stack templates, workflow templates, workflow groups, and workflow step templates.
- Ensures that resource names are generated dynamically, reducing potential conflicts in test environments.
…s are built

Verified against the platform: every `id` is a bare slug (derived from
resource_name unless set, slugged with a random suffix when the name is
not slug-shaped), while integration_id and auth need the /integrations/
prefix. auth also accepts /secrets/ and GIT_OTHER accepts only that form.
Stack template revisions take own-org template names only.
The bare connector id passed apply and failed every run in pre_0_step
with "Connector <id> does not exist". Rewrite the Resource IDs guide
around the id-vs-reference distinction, add the missing terraform_config
to the quickstart and onboarding workflows, and document the GIT_OTHER
secrets-only rule and the run-time failure in Troubleshooting.
The platform has no VAULT_SECRET kind. The docs presented it as the safe
place for a credential and described config.secret_id as taking a
/secrets/<name> path, so anyone following either ended up with a config
the platform silently never resolves.

Environment variable kind is PLAIN_TEXT; a secret goes in text_value as a
${secret::<name>} reference. The SDK still carries the enum value, so the
schema is untouched and the constants test now asserts the description
does not offer it.
The platform resolves four ${...} forms at run time and the provider
documented one of them, ${secret::<name>}, as if it were the whole story.
${workflow::}, ${ext-secret::azure-kv::} and ${reference::} appeared
nowhere, though they go in the same attributes.

Adds a Runtime References guide as the single place the syntax is written
down: the four forms, the $$ escaping Terraform needs, how ${workflow::}
changes shape between Terraform and custom workflows, and when to reach
for the outputs data sources instead. There is no ${stack::} form, so the
guide says so.

Attribute descriptions now carry a pointer to the guide rather than a
copy of any form, so the two cannot drift. wf_step_input_data.data gets
it for the first time, and the three hand-written "Input data as a JSON
string." descriptions on stack_template_revision now use the shared
constant. Tests pin the forms in the guide and the pointer on every
attribute that accepts one.
The description explained the TERRAFORM-/OPENTOFU- prefix the API stores
internally, which a reader can neither see nor act on, and never answered
the two questions people actually arrive with: which versions exist, and
what supplies them.

OpenTofu takes any version. Terraform is limited to the open-source
releases, 1.5.7 and earlier; anything later is BUSL-licensed and is only
available on a workflow step template built on your own runtime image.
The step's container ships a set of versions preinstalled and downloads
anything else when the workflow runs, if it exists upstream.

Also drops the "1.9.x" wildcard from the workflow_git example, which
cannot work on the stock container.
@hllvc
hllvc merged commit 0bbab22 into main Sep 15, 2026
1 check passed
@akorohodstckg
akorohodstckg deleted the fix/docs branch September 16, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants