Octoform 0.3.1 behavior baseline¶
This document records the behavior shipped in @hector21/octoform@0.3.1.
It is an audit baseline for documentation and compatibility work, not a roadmap.
Future multi-owner and organization governance work is intentionally absent.
The evidence was collected from the published npm artifact, its generated type
declarations, the source commit tagged v0.3.1, the test suite, and the GitHub
API descriptions identified below. When prose and executable behavior differ,
this baseline reports the executable behavior.
Published artifact¶
| Property | Observed value |
|---|---|
| Package | @hector21/octoform@0.3.1 |
| npm integrity | sha512-jP3YhMyq9+DF+Jw9JRSTG/66pZg+0J2nsAnorJd0ktMZyJwsAfj8kXCvjFlIVrUtsm/q+WiaDQ94ubZjqi9K9w== |
| npm shasum | 93d42cb44696ff1d9d1d692a5655b434a3a849f5 |
| Packed size | 71,428 bytes |
| Unpacked size | 257,062 bytes |
| Entries | 62 |
| Runtime | ESM, Node.js 20 or newer |
| Executable | octoform → bin/octoform.js |
The artifact contains bin/, compiled dist/ JavaScript and declarations,
source maps, documentation, examples, README, changelog, license, and package
metadata. It does not contain src/ or test/. A clean installation imports
the package and executes octoform --help successfully.
CLI surface¶
| Command | Options | Read/write contract | Observed successful exit |
|---|---|---|---|
audit |
--config |
Read-only inventory and findings | 0, including findings |
plan |
--config, --repo, --type |
Read-only desired/current diff | 0 |
apply |
--config, --repo, --type, --yes |
Shows a plan, confirms, then mutates | 0 when all changes apply |
classify |
--config, --apply |
Proposes types; writes property values only with --apply |
0 |
properties sync |
--config |
Creates/updates the organization custom-property schema and values | 0 |
Global aliases are -h for --help and -y for --yes. The default
configuration path is octoform.yml. Tokens are read from GITHUB_TOKEN, then
GH_TOKEN. There is no JSON output mode in v0.3.1.
Observed argument and exit behavior¶
| Invocation | Exit | Output behavior |
|---|---|---|
octoform |
2 |
Usage on standard output |
octoform --help |
0 |
Usage on standard output |
octoform plan --help |
0 |
Global usage on standard output |
octoform --nonsense |
2 |
Error on standard error, usage on standard output |
| option without its value | 2 |
Error on standard error, usage on standard output |
| invalid configuration or authentication | 1 |
Diagnostic on standard error |
declined apply |
1 |
No mutation |
partially or fully failed apply |
1 |
Per-change results are reported |
Command and subcommand names are checked only after configuration loading and
client creation. Consequently, an unknown command or invalid properties
subcommand can return configuration/authentication exit 1 before it reaches
the intended usage exit 2. This contradicts the unconditional wording in the
current exit-code reference and is a confirmed v0.3.1 limitation.
Configuration surface¶
Every scalar policy is unmanaged when omitted. Managed values layer in this
order: defaults, the repository's resolved types.<type>, then
repos.<name>. null cancels an inherited scalar and resolves to unmanaged.
An empty configuration fragment does not change a repository.
| Block | Fields and behavior |
|---|---|
| root | owner, imports, defaults, types, repos, exclude, classify, audit |
exclude |
Repository names removed from inventory and all later processing |
classify |
Custom-property name and first-match rules by file, shallow JSON, and visibility |
audit |
Description, topics, maximum topics, and type expectations; never mutates |
manage |
false keeps a repository visible to audit but suppresses policy planning |
features |
issues, wiki, projects, discussions |
merge |
squash, merge commit, rebase, auto-merge, update branch, delete branch after merge |
security |
vulnerability alerts, automated fixes, private reporting, secret scanning, push protection, code-scanning default setup |
repo |
description, homepage, topics, forking, web commit sign-off |
default_branch |
desired name and guarded rename_from allowlist |
ensure_branches |
Creates missing branches from the current default branch |
rulesets |
Named active branch rulesets with target branches, approvals, checks, force-push block, deletion block |
environments |
Named environments and required user reviewers |
files |
create-if-missing only, with local source resolved relative to its declaring file |
Imports resolve relative to the declaring YAML file, can import other files,
and reject cycles. Imported fragments may omit owner; the final resolved
configuration must contain one owner. Object fields merge recursively, while
declared arrays replace the inherited array at their policy level.
Desired-state coverage¶
| Resource | Read | Plan | Apply | Important boundary |
|---|---|---|---|---|
| Repository features | Yes | Yes | Yes | Discussions are read but not written by REST in this version |
| Merge settings | Yes | Yes | Yes | Applied in one repository settings patch |
| Repository metadata/topics | Yes | Yes | Yes | Topics use their dedicated endpoint |
| Security toggles | Yes | Yes | Yes | Unreadable state blocks rather than assumes disabled |
| Default branch | Yes | Yes | Yes | Rename requires rename_from; affected workflow files are named |
| Ensured branches | On demand | Yes | Yes | Created from the current default branch SHA |
| Rulesets | On demand | Yes | Yes | Only modeled rules are compared; unknown remote rules are preserved conceptually |
| Environments | On demand | Yes | Yes | Team reviewers are unreadable and block replacement |
| Files | On demand | Yes | Yes | Missing-only; no overwrite or deletion |
| Repository type property | Yes | Yes | classify --apply / properties sync |
Organization custom property; personal fallback is local config |
| Audit expectations | Yes | Findings | Never | Findings still exit 0 |
Archived repositories are inventoried but policy planning skips them. A policy
with manage: false is also skipped. --repo and --type narrow plan/apply;
they do not change desired values.
GitHub API usage¶
v0.3.1 does not send X-GitHub-Api-Version. GitHub therefore applies the
documented default 2022-11-28. That API version remains supported until
2028-03-10, but relying on an implicit default is a compatibility risk and must
be treated separately from this behavior audit.
The implementation uses REST only. It makes no GraphQL request in v0.3.1.
Inventory and discovery¶
| Purpose | REST operation |
|---|---|
| Scope inspection/authenticated identity | GET /user |
| Owner kind and organization plan | GET /orgs/{org} |
| Organization repositories | GET /orgs/{org}/repos |
| Own personal repositories | GET /user/repos |
| Another user's public repositories | GET /users/{username}/repos |
| Repository details/settings | GET /repos/{owner}/{repo} |
| Organization ruleset capability probe | GET /orgs/{org}/rulesets |
| Private repository ruleset capability probe | GET /repos/{owner}/{repo}/branches/{branch}/protection |
Repository state reads¶
| Resource | REST operation |
|---|---|
| Vulnerability alerts | GET /repos/{owner}/{repo}/vulnerability-alerts |
| Automated security fixes | GET /repos/{owner}/{repo}/automated-security-fixes |
| Private vulnerability reporting | GET /repos/{owner}/{repo}/private-vulnerability-reporting |
| Code-scanning default setup | GET /repos/{owner}/{repo}/code-scanning/default-setup |
| Branch existence | GET /repos/{owner}/{repo}/branches/{branch} |
| Environments | GET /repos/{owner}/{repo}/environments |
| Ruleset summaries/details | GET /repos/{owner}/{repo}/rulesets, GET /repos/{owner}/{repo}/rulesets/{ruleset_id} |
| Files and workflow contents | GET /repos/{owner}/{repo}/contents/{path} |
| Git reference | GET /repos/{owner}/{repo}/git/ref/{ref} |
| Organization property values | GET /orgs/{org}/properties/values |
| Reviewer identity | GET /users/{username} |
Mutations¶
| Resource | REST operation |
|---|---|
| Repository settings and selected security analysis fields | PATCH /repos/{owner}/{repo} |
| Topics | PUT /repos/{owner}/{repo}/topics |
| Vulnerability alerts | PUT or DELETE /repos/{owner}/{repo}/vulnerability-alerts |
| Automated security fixes | PUT or DELETE /repos/{owner}/{repo}/automated-security-fixes |
| Private vulnerability reporting | PUT or DELETE /repos/{owner}/{repo}/private-vulnerability-reporting |
| Code-scanning default setup | PATCH /repos/{owner}/{repo}/code-scanning/default-setup |
| Default branch rename | POST /repos/{owner}/{repo}/branches/{branch}/rename |
| Branch creation | POST /repos/{owner}/{repo}/git/refs |
| Environment create/update | PUT /repos/{owner}/{repo}/environments/{environment_name} |
| Ruleset create/update | POST /repos/{owner}/{repo}/rulesets, PUT /repos/{owner}/{repo}/rulesets/{ruleset_id} |
| File creation | PUT /repos/{owner}/{repo}/contents/{path} without sha |
| Custom-property schema | PUT /orgs/{org}/properties/schema/{custom_property_name} |
| Custom-property values | PATCH /orgs/{org}/properties/values |
Authentication and permissions¶
The CLI's classic-token preflight requires repo for every command. Mutating
organization property commands additionally require admin:org. Fine-grained
tokens do not expose x-oauth-scopes; absence of that header bypasses the
classic-scope check, and each API endpoint remains the authority.
The documented scopes are a coarse v0.3.1 contract, not a minimum
fine-grained permission matrix. Repository settings, administration, contents,
environments, rules, security events, organization rules, and custom properties
can require different fine-grained permissions and owner roles. The versioned
documentation must describe those per capability instead of claiming that one
classic scope statement precisely covers every token type.
Confirmed limitations and documentation corrections¶
- Unknown command/subcommand validation occurs too late and can report exit
1for missing config/token instead of usage exit2. - REST API version selection is implicit (
2022-11-28), not pinned in the client. - Discussions can be observed but not applied because the implementation has no GraphQL transport and the setting is not writable through the used REST repository update contract.
- Environment reviewer policies model users only. An existing team reviewer makes the field unreadable and blocks a change.
- Rulesets model only branch target/include conditions, approvals, status checks, force-push blocking, and deletion blocking.
- Personal accounts do not have organization custom properties; repository types must come from configuration there.
- Classic scope documentation is not a fine-grained permission matrix.
auditreports findings but deliberately cannot gate CI through its exit code.- No machine-readable CLI output or stable diagnostic-code contract exists.
- No repository, ruleset, environment, file, or access removal is inferred from omission; file management is create-if-missing only.
Upstream API evidence¶
| Evidence | Value |
|---|---|
| Effective unversioned REST default | 2022-11-28 |
| Current audited REST description | 2026-03-10 |
| OpenAPI repository commit | b26c240ded1c8b79cb0fb09dee4a21239061fa23 |
| Bundled OpenAPI SHA-256 | 6f36bc90e67dedbdb256880d0c5daaaba0afa8ce7bde343db7cc7f608492a997f |
| REST operations in full description | 1,220 |
| Mutating REST operations in full description | 584 |
| GraphQL mutations observed during audit | 274, including 16 deprecated |
Primary sources:
The complete endpoint disposition register is generated from reviewed metadata and the pinned API descriptions. It covers the owner/repository scopes relevant to Octoform and records why every operation is declarative, sensitive declarative, operational, observational, or excluded.