This chapter is for someone changing roc-automation itself: its manual or its shared actions. It assumes the rest of the manual.
Propose a change§
Use issues for bug reports and design discussion, and pull requests for
changes. Explain the affected behavior, the change, and how it was validated.
Report vulnerabilities privately, as SECURITY.md describes. Commits are
signed, and changes reach the default branch through pull requests.
Change the manual§
The sources are the AsciiDoc files under docs/.
Write for the shared renderer
lists the conventions they follow.
Build the site, PDF and static Markdown locally with a precompiled renderer:
/path/to/roc-docs build --workspace . --pdf-filename roc-automation.pdf --docs-version 3
The output is written to .docs-out/. The Documentation workflow runs the
same build on every pull request and deploys from the default branch. Upstream
CI builds and caches the renderer; downstream consumers supply the released
binary. To develop the renderer itself, follow
Maintain the documentation renderer
for its compiler, dependencies, architecture and verification procedures.
The action uses the shared renderer and built-in theme. Python is used by the
independent test harness; rendering does not invoke it.
Apply the editorial review to the affected chapter, README and contributor guide. Delete material without a current reader purpose instead of moving it to an archive chapter.
Explain the risk and control where they apply§
For a change to automation behavior, a workflow boundary or an evidence claim, update the relevant chapter’s risk-and-control narrative. State a concrete failure or attack scenario, the guiding principle, the mechanism that addresses it, the test or observation that verifies it, and the assumptions that remain. Name the affected source, compiler, artifact, target or authority when it matters. Explain a tradeoff in terms of that risk rather than a framework score.
Use connected prose beside the operational guidance. Do not add a generic security checklist to every task or duplicate command reference material. Keep the explanation specific to the chapter. Update the reference mapping when a risk or control moves, gains another owner chapter or changes its verification. The reference links to the authoritative narrative instead of maintaining a second copy of its rules.
Review failures as well as the happy path. Useful regressions demonstrate that wrong identities, stale or incomplete evidence, unsafe paths and interrupted execution cannot become a pass or privileged operation. A configuration check establishes configuration; runtime and operational claims need corresponding execution or observation. Describe intended practice without asserting that an unimplemented utility already provides it.
Investigate before expanding the model§
Further investigations use a scoped agent task whose outputs are a concrete proposal and a GitHub issue, creating or updating the appropriate issue rather than duplicating it. Give the agent a realistic scenario to investigate, the affected boundary, primary sources to consult, and existing behavior to inspect. Ask it to assess applicability, failure modes, cost, alternatives and residual assumptions, with proposed changes and acceptance evidence. Separate verified findings from hypotheses. Keep private vulnerability details in the private reporting channel.
Maintainers review the result before turning it into normative guidance or implementation. Investigation findings and implementation gaps stay in issues; the manual records the chosen practice and rationale. Do not create framework requirements, governance policy or product-specific security promises as an incidental outcome of an automation investigation.
Change a shared action§
Read the trust model first. It is normative: a change to an action’s behavior or permissions keeps those boundaries and arrives with regression tests for them. Controller implementation references live beside their source, separate from the consumer manual.
actions/nightly-report and actions/publish-release are Roc scripts,
scripts/nightly_report.roc and scripts/publish_release.roc, and their tests
are expect tests that blueprint run check runs;
Change an action that is a Roc script
says how they are built and tested. The documentation action invokes the native
renderer through its shell wrapper. Other controllers and the independent test
harnesses use Python. Python 3.10 or later and the standard library are sufficient
for their tests:
python3 -m unittest discover -s tests -v
Add regression tests for fixes and tests for new behavior, especially for stale commit or run evidence, branch ownership, permissions and malformed input.
Keep each token permission on the job that needs it.
Never execute candidate code in a job that can write.
Pin external actions and workflows to full commit SHAs. Use
$/actions/NAMEfor actions in this repository, inheriting the containing workflow or action’s immutable revision without resolving against the caller workspace.Use the standard library unless an additional runtime dependency has an explicit justification.
Review dependency changes and address actionable static-analysis findings.
Change a script§
The repository’s own automation is Roc scripts under scripts/, written as
Write product-specific automation as Roc scripts
describes. With blueprint installed as
Get blueprint describes:
blueprint run check
It runs the expect tests of the modules under scripts/src/, checks each
script with roc-stable, checks their formatting, and holds every script’s
roc field to the release Blueprint.roc names. CI runs the same task.
scripts/check_settings.roc must stay read-only. Its one request function
states the GET method, and what it decides from GitHub’s answers is pure
logic in scripts/src/Settings.roc. A change to a check arrives with expect
tests for the passing and the failing answer, and a setting that cannot be read
is reported as unknown. CI does not run it against a repository, because that
needs administration access; see
Confirm the settings.
Change an action that is a Roc script§
scripts/nightly_report.roc and scripts/publish_release.roc run with write
tokens, so they are held to
What the jobs with write access run
and to the rules for every shared action.
Every decision is in a module without effects: scripts/src/NightlyReport.roc,
scripts/src/PublishRelease.roc, and scripts/src/GitHub.roc for the gh
invocation and the checks the two share. A module checks the inputs into a
plan, and then decides one step at a time: given the answer to the last
request, it names the next request or the end. The script only carries each
request to gh, or to the runner’s disk, and brings the answer back.
A change to a validation rule, to the order of the requests, to what a failure leaves behind or to an error message arrives with an
expecttest. The tests drive the same step functions against a pretend repository and compare the whole sequence of requests, so none of them reaches GitHub.Keep the method of every request stated in
GitHub.args, and the token out of every plan, argument and message.ghreads it fromGH_TOKEN.A local check comes before the first request. In
PublishReleasethe local steps and the requests are different types, so a step that reads GitHub cannot be placed among the local checks.The privileged actions invoke the sibling installer directly with their own repository root as
GITHUB_WORKSPACE. Preserve this isolation: the consumer’s Blueprint must never configure the privileged report or publication tools.
To run a script by hand, give it the environment the action gives it: the
inputs as INPUT_*, the token as GH_TOKEN, and the runner’s GITHUB_*
variables. A pass with a title that no issue has only lists issues:
GH_TOKEN="$(gh auth token)" GITHUB_REPOSITORY=<owner>/<name> \
GITHUB_SERVER_URL=https://github.com GITHUB_RUN_ID=1 GITHUB_OUTPUT=/tmp/outputs \
INPUT_OUTCOME=success INPUT_NIGHTLY_TAG=probe INPUT_RELEASE_TAG=0.0.0 \
INPUT_TITLE='nightly-report probe, never opened' \
blueprint run nightly-report
ci.yml runs actions/nightly-report itself with those inputs, in a job whose
token can only read issues. No job there holds a token that can write issues or
releases, so the requests that write are covered by the expect tests and not
by a run against GitHub.
Release the tools§
The tools release includes the action programs, roc-policy, roc-docs and
the published-release compatibility runner. Release tools defines each tool’s
build targets and native acceptance matrix. To build the Linux action programs
locally:
blueprint run build-tools
This writes dist/<tool>-<system> for x86_64-linux and aarch64-linux.
Other utilities use their own build entrypoints; see their maintenance references.
The workflow publishes under tools-<version> after read-only build jobs and
native tests of the exact artifacts. Tests run without a checkout, Nix or build
compiler, using the complete distributed runtime and declared external helpers.
The dispatch-only publisher receives those files as inert bytes through
actions/publish-release.
A pull request builds and tests as a dry run. Before dispatching a release,
commit its notes as docs/releases/tools-<version>.md; remove the source notes
when the published release owns them.
Release a shared action§
Repositories reference an action by full commit SHA and adopt a new one through a Dependabot or maintainer pull request. Nothing updates them automatically.
Shared workflows and composite actions reference sibling actions with GitHub’s
$/ syntax. The consumer’s full workflow SHA fixes the complete shared
implementation, including the installer and its checksum registry. Change the
action, workflow and tests together; there is no separate internal pin to bump.
External dependencies still require reviewed full SHAs. This composition targets
GitHub.com; $/ is not supported on GitHub Enterprise Server.
Use a unique version tag for a published release, record any assigned vulnerability identifiers for fixes, and never move an existing tag.