@rmyndharis/aimhooman 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +201 -5
- package/CONTRIBUTING.md +43 -30
- package/README.md +14 -14
- package/SECURITY.md +8 -10
- package/bin/aimhooman.mjs +99 -28
- package/package.json +1 -1
- package/rules/attribution.json +7 -7
- package/src/atomic-write.mjs +32 -1
- package/src/git-environment.mjs +10 -0
- package/src/githooks.mjs +114 -20
- package/src/gitx.mjs +48 -277
- package/src/history-scan.mjs +4 -1
- package/src/hook.mjs +145 -9
- package/src/scan-session.mjs +2 -1
- package/src/scan-target.mjs +51 -23
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,204 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.1.2] - 2026-07-17
|
|
9
|
+
|
|
10
|
+
### Removed
|
|
11
|
+
|
|
12
|
+
- The legacy per-clone state migration is gone, and with it the failure paths it
|
|
13
|
+
created. `openRepo` used to look for state under `.git/worktrees/<name>/aimhooman`
|
|
14
|
+
and migrate it into `<commonDir>/aimhooman`, fingerprinting both and refusing to
|
|
15
|
+
continue when two copies disagreed. No released version ever wrote to that
|
|
16
|
+
location — v0.1.0 already resolved state to `<commonDir>/aimhooman` on the line
|
|
17
|
+
above the migration — so the predecessor it protected never existed. What it did
|
|
18
|
+
produce was real: any error other than ENOENT while listing `.git/worktrees` was
|
|
19
|
+
re-raised through every command, including `uninstall`, so a directory Git itself
|
|
20
|
+
reads without trouble could freeze a repository with no supported way out.
|
|
21
|
+
`.git/worktrees` belongs to Git and can be owned by another uid after a
|
|
22
|
+
`sudo git worktree add`. Repository state resolves to `<commonDir>/aimhooman`, as
|
|
23
|
+
it always has.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Unstaging residue no longer stages the deletion of tracked files. The HEAD probe
|
|
28
|
+
reused the options object carrying the pathspec on stdin, and `git rev-parse`
|
|
29
|
+
never reads stdin, so once the pathspec passed the 64 KiB pipe buffer the write
|
|
30
|
+
failed with `EPIPE`. The catch read that as "this repository has no HEAD" and ran
|
|
31
|
+
`git rm --cached` where `git restore --staged` was meant, staging the deletion of
|
|
32
|
+
every tracked path it had been asked to restore, printing "unstaged N AI
|
|
33
|
+
artifact(s)", and exiting 0 so the commit carried the deletions into history. It
|
|
34
|
+
takes roughly 470 paths to cross that buffer, which a tracked `.claude/projects/`
|
|
35
|
+
tree passes without trying, and the repair loop could not see it: the staged
|
|
36
|
+
deletions read as still-staged, so it retried, made no progress, and reported
|
|
37
|
+
success anyway. The probe no longer receives the pathspec, and only git's own exit
|
|
38
|
+
status may pick the branch — a timeout or a missing git stops the commit instead
|
|
39
|
+
of guessing that HEAD is absent. Present since 0.1.0.
|
|
40
|
+
- A stuck `git` no longer holds a repository open indefinitely. `execFileSync` has
|
|
41
|
+
no default timeout, so a child that never exited blocked its caller for as long as
|
|
42
|
+
it lived, with nothing printed and nothing logged; one held a CI runner for six
|
|
43
|
+
hours and died to the platform's ceiling rather than to anything here. Every child
|
|
44
|
+
process now carries a bound: 120 seconds for git, far above any real call, and 5
|
|
45
|
+
seconds for the `ps` identity probe, which runs inside the lock retry loop and only
|
|
46
|
+
on macOS and BSD (Linux reads `/proc`, Windows returns early). Both throw into the
|
|
47
|
+
handling that was already there, so a bounded failure degrades the way a missing
|
|
48
|
+
git already did instead of hanging. A test walks `src/` and `bin/` and fails on any
|
|
49
|
+
child process without a bound.
|
|
50
|
+
- Renaming or moving a repository no longer freezes it. The dispatcher bakes
|
|
51
|
+
absolute paths, so a move changes the `CHAINED` value it carries, and ownership
|
|
52
|
+
was decided by comparing that string — overruling the SHA-256 fingerprint on the
|
|
53
|
+
line above, which had already proved the file was ours. Every commit, every
|
|
54
|
+
`--no-verify`, and every branch creation then failed; `status` reported the guard
|
|
55
|
+
as belonging to another repository; `aimhooman init`, the remedy each message
|
|
56
|
+
named, refused too. Ownership inside the repository's own `.git` is now settled
|
|
57
|
+
by the fingerprint alone, because no second repository can own a file there. The
|
|
58
|
+
baked path keeps its vote only where a hooks directory can genuinely be shared —
|
|
59
|
+
two repositories pointing `core.hooksPath` at one place — which is the case it
|
|
60
|
+
was written for.
|
|
61
|
+
- `uninstall` no longer reports success while leaving its own dispatchers behind.
|
|
62
|
+
Refusals were recorded as warnings, the exit code only consulted failures, and
|
|
63
|
+
the "uninstalled" headline printed before either was known, so a moved
|
|
64
|
+
repository was told it was free while four dispatchers still blocked every
|
|
65
|
+
commit. uninstall now checks the hooks directory instead of trusting its own
|
|
66
|
+
report: anything of ours still on disk is named with its full path, the headline
|
|
67
|
+
is withheld, and the exit code is 30. A chained backup that is a symlink is
|
|
68
|
+
still never read or copied through, but the dispatcher above it is now removed
|
|
69
|
+
rather than held as collateral, and the report says the original hook was not
|
|
70
|
+
restored.
|
|
71
|
+
- A `HOME` behind a symlink no longer makes every global dispatcher look foreign.
|
|
72
|
+
`hookDiagnostics` compared the effective hooks directory to the global one with
|
|
73
|
+
`resolve`, which does not follow symlinks, while Git reports the realpath — so
|
|
74
|
+
on a distribution that ships `/home` as a link, or an NFS or autofs home, the
|
|
75
|
+
two spellings differed and every global hook was diagnosed as managed for
|
|
76
|
+
another repository.
|
|
77
|
+
- A failed excludes refresh no longer disables the `PreToolUse` guard. Writing
|
|
78
|
+
`.git/info/exclude` sat inside the same `try` as the engine load, and the shared
|
|
79
|
+
`catch` allowed the command on every non-strict profile, so an unwritable
|
|
80
|
+
`.git/info` — a CI checkout, a read-only volume, a repository owned by another
|
|
81
|
+
user — turned a staged AWS key plus `git commit --no-verify` from `deny` into
|
|
82
|
+
`allow`. Nothing about the policy was wrong: the rules had loaded, and the
|
|
83
|
+
reported cause ("could not load policy rules") named the wrong thing. Refreshing
|
|
84
|
+
the excludes is gitignore hygiene, which `pre-commit` never does and still
|
|
85
|
+
answers correctly, so it now runs outside the verdict and reports as a warning.
|
|
86
|
+
|
|
87
|
+
- A local rule pack that cannot load no longer produces a report claiming a
|
|
88
|
+
complete scan. `strict` already failed closed, but `clean` and `compliance`
|
|
89
|
+
turned the load error into a stderr warning and left the accumulator untouched,
|
|
90
|
+
so `--json` returned `complete: true`, `findings: []`, `skipped: {}` and exit 0
|
|
91
|
+
while the team's own rules had never run. The pack most teams write is a
|
|
92
|
+
detector for their internal token format; one typo took it out of the scan, and
|
|
93
|
+
the report actively certified that nothing was missed. A failed pack is now the
|
|
94
|
+
counted skip reason `local-pack-error` and marks the scan incomplete, which is
|
|
95
|
+
the treatment `local-input-limit` already had in every profile: a rule that
|
|
96
|
+
never ran is a coverage gap, not an empty result. `clean` and `compliance`
|
|
97
|
+
therefore stop at exit 31 where they previously continued. The hint now points
|
|
98
|
+
at the pack instead of suggesting the caller reduce the target or limits, which
|
|
99
|
+
was never the remedy for a pattern that will not compile.
|
|
100
|
+
- Creating a branch no longer rescans the entire repository. A new branch arrives
|
|
101
|
+
with an all-zero old tip, so `rev-list` ran with no negative boundary and every
|
|
102
|
+
ancestor was re-read, tree and blob sizes included: 24.7s at 200 commits, growing
|
|
103
|
+
linearly, on an operation `--no-verify` cannot skip. Reachability from
|
|
104
|
+
`refs/heads/*` is now trusted, because those commits passed this same guard when
|
|
105
|
+
their branch was written, which puts `git checkout -b` back at ordinary commit
|
|
106
|
+
cost (0.95s in the same repository). Only `refs/heads/*` counts: tags and remote
|
|
107
|
+
refs are not gated here and still cannot pre-poison reachability, the refs under
|
|
108
|
+
review are never their own proof, and a commit no local branch reaches is still
|
|
109
|
+
scanned in full. Commits that predate `aimhooman init` are outside the guard's
|
|
110
|
+
scope; audit them with `check --range`.
|
|
111
|
+
- `init` no longer writes dispatchers into a hooks directory that Git tracks.
|
|
112
|
+
Ownership was tested by location alone, so any `core.hooksPath` inside the
|
|
113
|
+
worktree counted as the repository's own — including the committed `.husky` and
|
|
114
|
+
`.githooks` directories that husky and the vanilla pattern rely on. init edited
|
|
115
|
+
those tracked files in place, and the dispatcher it wrote carries this machine's
|
|
116
|
+
absolute CLI, Node, and PATH: once committed, the hook is dead for every
|
|
117
|
+
teammate, and the PATH alone discloses the author's home directory and installed
|
|
118
|
+
tooling. Ownership now also requires that Git is not tracking the directory, and
|
|
119
|
+
a directory Git cannot be asked about counts as tracked. A refusal now names the
|
|
120
|
+
cause instead of reporting a bare incomplete installation; as before, integrate
|
|
121
|
+
aimhooman into the existing hook manager or remove the override.
|
|
122
|
+
- A moved Node interpreter no longer disables the guard silently. 0.1.1 made the
|
|
123
|
+
dispatcher degrade gracefully when the CLI or Node was missing, which is right
|
|
124
|
+
for a half-removed install but wrong for a relocated interpreter: `brew upgrade
|
|
125
|
+
node`, `nvm`, `fnm`, and `volta` all move the `process.execPath` that `init`
|
|
126
|
+
pins, and every hook then warned once and allowed the commit unprotected. The
|
|
127
|
+
conditions now separate by what the user can still do about them. A missing CLI
|
|
128
|
+
still allows the operation, because the package is gone and no guard is wanted.
|
|
129
|
+
A missing pinned interpreter stops the operation and names the path and the
|
|
130
|
+
remedy — but only while a Node exists to run that remedy with, since `init` and
|
|
131
|
+
`uninstall` are both Node programs and the CLI file is inert without one.
|
|
132
|
+
Where no Node is present at all, the dispatcher degrades and says so, because
|
|
133
|
+
refusing there would leave the repository unusable with no supported way to
|
|
134
|
+
remove the hooks. Stopping matches what the CLI already believed —
|
|
135
|
+
`installedHooks` treats an unreachable Node as an inactive dispatcher, so the
|
|
136
|
+
shell was short-circuiting the CLI's own fail-closed path — but only where
|
|
137
|
+
stopping is recoverable. Re-run `aimhooman init` after upgrading Node to re-pin it.
|
|
138
|
+
- Attribution rules no longer miss current AI footers. `attribution.generated-with`
|
|
139
|
+
pinned the literal vendor link `https://claude.ai/code`, and the co-author rules
|
|
140
|
+
pinned the display names `Claude`, `Claude Code`, and `Codex`. Once the link was
|
|
141
|
+
rebranded and the display name grew a model suffix, the default footer passed
|
|
142
|
+
through untouched with exit 0 while the older form was still repaired perfectly.
|
|
143
|
+
The rules now anchor on what identifies the machine rather than what marketing
|
|
144
|
+
changes: a co-author trailer is matched by its `noreply@` service address alone,
|
|
145
|
+
and the generated-with link is matched by its shape. A new contract test rejects
|
|
146
|
+
any attribution pattern that pins a vendor URL, so the pack cannot rot back into
|
|
147
|
+
this state without failing CI.
|
|
148
|
+
- `attribution.ai-noreply` no longer backtracks catastrophically. `\s*[^<>]+\s*`
|
|
149
|
+
placed three ambiguous quantifiers before a literal `<`, which cost 49s on a
|
|
150
|
+
6400-character trailer that never closes; built-in patterns are exempt from the
|
|
151
|
+
local input cap, so a commit message reached it directly. The redundant
|
|
152
|
+
whitespace quantifiers are gone (`[^<>]+` already spans them), leaving the
|
|
153
|
+
matched language unchanged, and a bounded-cost test now covers the built-in
|
|
154
|
+
message patterns.
|
|
155
|
+
|
|
156
|
+
## [0.1.1] - 2026-07-16
|
|
157
|
+
|
|
158
|
+
### Fixed
|
|
159
|
+
|
|
160
|
+
- Git hooks no longer trap the repository when the aimhooman CLI or Node is
|
|
161
|
+
missing (for example after the package was removed without `aimhooman
|
|
162
|
+
uninstall`). The dispatcher used to exit 127 and abort every commit; it now
|
|
163
|
+
warns once and allows the operation without protection, so a half-removed
|
|
164
|
+
install degrades gracefully instead of breaking Git.
|
|
165
|
+
- The `PreToolUse` guard no longer denies ordinary read-only pipelines. Any pipe
|
|
166
|
+
made the parsed command uncertain, and the clean and compliance profiles read
|
|
167
|
+
that uncertainty as a possibly hidden commit, so everyday lines such as
|
|
168
|
+
`gh issue view 1 | tail -5` were blocked. A pipeline now passes when every
|
|
169
|
+
segment is a known read-only command and the line carries no opaque shell
|
|
170
|
+
syntax; everything else stays denied, including pipe-to-shell, subshells,
|
|
171
|
+
`eval`, and readers that execute their own input. `strict` is unchanged.
|
|
172
|
+
- A bare `allow <path>` for a path that matches a secret rule (for example
|
|
173
|
+
`.env.minimal`) no longer reports success while leaving the block in place.
|
|
174
|
+
It now fails closed and directs to `--scope secret-path`, the only scope that
|
|
175
|
+
can silence a secret, so a local override cannot hide a possible leaked key.
|
|
176
|
+
- Detect secrets renamed to a neutral path. A path-only secret such as `.env`
|
|
177
|
+
was missed when moved to a name the destination scan does not match, because its
|
|
178
|
+
content carries no PEM, AWS, or token shape; the rename-source review now retains
|
|
179
|
+
secret-category findings and reports them on the destination path where the bytes
|
|
180
|
+
live, so clean-profile repair unstages the blob that carries the secret. Deleting
|
|
181
|
+
a secret path remains a non-finding.
|
|
182
|
+
- Retry the atomic rename that commits a state write when Windows reports a
|
|
183
|
+
transient `EPERM`, `EACCES`, or `EBUSY`. An antivirus or indexer holding a
|
|
184
|
+
handle on the file aimhooman had just written could kill a lock contender at
|
|
185
|
+
its ticket publication, which surfaced as unrelated failures (a lifecycle-queue
|
|
186
|
+
timeout, or a repair that appeared not to run). A persistent failure, any other
|
|
187
|
+
error code, and every non-Windows platform still fail immediately, and the
|
|
188
|
+
original file is never left partially written.
|
|
189
|
+
- The clean-profile repair now verifies it cleared every target and re-runs the
|
|
190
|
+
unstage when a transient git operation under heavy load left a path staged, so
|
|
191
|
+
the repair no longer reports success while an artifact rides through.
|
|
192
|
+
- Derive the post-repair empty-commit hint from the staged paths captured
|
|
193
|
+
before repair instead of a second git read after `git restore --staged`. That
|
|
194
|
+
read followed an index write and could transiently report the wrong state
|
|
195
|
+
under heavy load; the derivation is deterministic.
|
|
196
|
+
|
|
197
|
+
### Changed
|
|
198
|
+
|
|
199
|
+
- The release workflow runs `npm run verify` before publish instead of `npm test`,
|
|
200
|
+
so the tarball-manifest check and the installed-hook smoke test gate the published
|
|
201
|
+
tag, matching the push workflow.
|
|
202
|
+
- Non-hook commands no longer load the PreToolUse shell parser at startup; it is
|
|
203
|
+
imported only for the `hook` subcommand, which speeds up `init`, `uninstall`,
|
|
204
|
+
`check`, `status`, and the rest and gives the lifecycle-lock queue more headroom
|
|
205
|
+
on slow runners.
|
|
9
206
|
|
|
10
207
|
## [0.1.0] - 2026-07-15
|
|
11
208
|
|
|
@@ -30,10 +227,9 @@ commit messages, and AI markers left in code.
|
|
|
30
227
|
- Scan every index stage during unresolved conflicts so a secret on either side
|
|
31
228
|
cannot be missed.
|
|
32
229
|
- Authorize protected-path CI only when the exact workflow-run attempt's actor and
|
|
33
|
-
triggering actor, including their IDs, match the
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
closed with no reviewer fallback.
|
|
230
|
+
triggering actor, including their IDs, match the repository owner returned by
|
|
231
|
+
GitHub. Bind that authorization to exact commits, paths, blobs, modes, deletion
|
|
232
|
+
tombstones, and policy migrations; changes not attributed to the owner fail closed.
|
|
37
233
|
- Keep the published local rule-pack schema compatible with strict JSON Schema
|
|
38
234
|
validators.
|
|
39
235
|
- Prove npm version absence and forward dist-tag movement with bounded retries
|
package/CONTRIBUTING.md
CHANGED
|
@@ -88,7 +88,39 @@ Personal, per-clone detection belongs in `<git-common-dir>/aimhooman/rules/*.jso
|
|
|
88
88
|
(local, never committed). Linked worktrees share it. Contribute general-purpose
|
|
89
89
|
rules to `rules/` instead.
|
|
90
90
|
|
|
91
|
-
##
|
|
91
|
+
## Commits
|
|
92
|
+
|
|
93
|
+
Subject lines follow [Conventional Commits](https://www.conventionalcommits.org/):
|
|
94
|
+
`type(scope): summary`.
|
|
95
|
+
|
|
96
|
+
| Type | Use for |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `feat` | a new rule, host adapter, or CLI capability |
|
|
99
|
+
| `fix` | a bug fix |
|
|
100
|
+
| `docs` | documentation only |
|
|
101
|
+
| `test` | tests and fixtures only |
|
|
102
|
+
| `refactor` | restructuring that leaves behavior identical |
|
|
103
|
+
| `perf` | a speedup you can measure |
|
|
104
|
+
| `ci` | workflows and release automation |
|
|
105
|
+
| `chore` | dependency bumps, version stamping, housekeeping |
|
|
106
|
+
|
|
107
|
+
Scopes track the project layout: `rules`, `hook`, `githooks`, `cli`, `state`,
|
|
108
|
+
`adapter`, `deps`, `release`. Drop the scope when a change spans several.
|
|
109
|
+
|
|
110
|
+
The `type(scope):` prefix is the only part that is a format. Everything after the
|
|
111
|
+
colon stays a plain imperative sentence that names what actually changed:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
fix(state): retry the rename when Windows reports a transient lock
|
|
115
|
+
fix(hook): allow Git operations when the aimhooman CLI or Node is missing
|
|
116
|
+
ci: run the test matrix once per change instead of twice
|
|
117
|
+
chore(release): 0.1.1
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
PRs land as squash merges, so the PR title is the commit message that lands on
|
|
121
|
+
`main`. Title the PR the same way.
|
|
122
|
+
|
|
123
|
+
### Policy (important)
|
|
92
124
|
|
|
93
125
|
This project keeps AI tooling residue out of history — **including its own**.
|
|
94
126
|
Commits must read as if a human wrote them:
|
|
@@ -100,45 +132,26 @@ Commits must read as if a human wrote them:
|
|
|
100
132
|
|
|
101
133
|
## Pull requests
|
|
102
134
|
|
|
103
|
-
1. Open a PR against `main`.
|
|
135
|
+
1. Open a PR against `main`. Title it `type(scope): summary` — it becomes the
|
|
136
|
+
commit message on `main`.
|
|
104
137
|
2. Include tests for any new behavior and run `npm run verify`.
|
|
105
138
|
3. Update `CHANGELOG.md` and `docs/` where relevant.
|
|
106
|
-
4. Make sure the PR follows the commit
|
|
139
|
+
4. Make sure the PR follows the commit conventions above.
|
|
107
140
|
|
|
108
141
|
By participating, you agree to abide by the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
109
142
|
|
|
110
|
-
|
|
111
|
-
workflow but no pull-request approval, code-owner review, last-push approval, or
|
|
112
|
-
other reviewer. The repository has no `CODEOWNERS` fallback.
|
|
113
|
-
|
|
114
|
-
Changes to agent instructions or `.aimhooman.json` are protected-path changes. CI
|
|
115
|
-
verifies the pinned repository and owner login plus numeric IDs through the GitHub
|
|
116
|
-
API, then fetches the exact workflow-run attempt. GitHub must attribute the
|
|
117
|
-
attempt's `actor` and `triggering_actor` to that owner's login and numeric ID. CI
|
|
118
|
-
binds that authorization to the exact
|
|
119
|
-
head, transition commit, path, resulting blob and regular-file mode, or deletion
|
|
120
|
-
tombstone. Policy migrations additionally bind the old and new policy objects.
|
|
121
|
-
Another commit, attempt, path result, mode, or migration needs fresh authorization.
|
|
122
|
-
A protected-path change by any non-owner fails closed.
|
|
123
|
-
|
|
124
|
-
The owner account and its credentials are the repository trust root. These checks
|
|
125
|
-
verify GitHub's actor attribution and bind the resulting objects; they do not prove
|
|
126
|
-
an interactive human action, provide independent review, or protect against a
|
|
127
|
-
compromised owner credential.
|
|
143
|
+
## Releases
|
|
128
144
|
|
|
129
145
|
Releases publish to npm automatically when a `v*` tag is pushed. The workflow
|
|
130
|
-
installs dependencies, runs the test suite, and publishes with npm build provenance
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
and the matching README version badge, then tag and push:
|
|
146
|
+
installs dependencies, runs the test suite, and publishes with npm build provenance.
|
|
147
|
+
To cut a release, bump the version (keep `package.json`, `.claude-plugin/plugin.json`,
|
|
148
|
+
`.codex-plugin/plugin.json`, and `.claude-plugin/marketplace.json` in sync), add the
|
|
149
|
+
`## [version]` CHANGELOG entry and the matching README version badge, then:
|
|
135
150
|
|
|
136
151
|
```sh
|
|
137
152
|
git tag -a v0.1.0 -m v0.1.0
|
|
138
153
|
git push origin v0.1.0
|
|
139
154
|
```
|
|
140
155
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
and rotate it regularly. Do not run `npm publish` or move dist-tags manually while
|
|
144
|
-
a release job is pending or running.
|
|
156
|
+
Use a granular, publish-only npm token with 2FA enabled, and avoid publishing or
|
|
157
|
+
moving dist-tags manually while a release job is running.
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
11
11
|
<img src="https://img.shields.io/github/actions/workflow/status/rmyndharis/aimhooman/test.yml?branch=main&label=CI" alt="CI">
|
|
12
|
-
<img src="https://img.shields.io/badge/version-v0.1.
|
|
12
|
+
<img src="https://img.shields.io/badge/version-v0.1.2-blue" alt="v0.1.2">
|
|
13
13
|
<img src="https://img.shields.io/badge/node-%E2%89%A522.8-339933?logo=node.js&logoColor=white" alt="Node 22.8+">
|
|
14
14
|
<img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="Zero dependencies">
|
|
15
15
|
<img src="https://img.shields.io/badge/license-MIT-111111" alt="MIT">
|
|
@@ -151,8 +151,10 @@ Prefer repository `init` unless the global ordering is understood.
|
|
|
151
151
|
|
|
152
152
|
When `core.hooksPath` is set, Git reads hooks only from that effective directory and
|
|
153
153
|
ignores `.git/hooks`. Repository `init` installs and chains predecessors only when
|
|
154
|
-
that directory is absent or is proven to be owned by the repository
|
|
155
|
-
modify a global, shared,
|
|
154
|
+
that directory is absent or is proven to be owned by the repository: inside it and
|
|
155
|
+
not tracked by Git. It refuses to modify a global, shared, external, or tracked
|
|
156
|
+
hook directory, because a dispatcher committed from one machine names paths that
|
|
157
|
+
exist only on that machine. In that case, integrate
|
|
156
158
|
aimhooman into the existing hook manager or remove the override before retrying.
|
|
157
159
|
|
|
158
160
|
Repository `init` installs `pre-commit`, `pre-merge-commit`, `commit-msg`, and
|
|
@@ -286,17 +288,15 @@ Under `strict`, policy files and agent instructions produce review-required find
|
|
|
286
288
|
The product's `review` and `policy-review` commands record local, object-bound decisions;
|
|
287
289
|
an ordinary path allow cannot satisfy either finding.
|
|
288
290
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
mode, or
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
fallback. The owner account and its credentials are the trust root, so this is owner
|
|
299
|
-
authorization, not independent review.
|
|
291
|
+
For a protected-path change, CI verifies the pinned repository and owner login plus
|
|
292
|
+
numeric IDs through the GitHub API, then inspects the exact workflow-run attempt.
|
|
293
|
+
GitHub must attribute both `actor` and `triggering_actor`, including their numeric IDs,
|
|
294
|
+
to that owner. CI then binds the authorization to the exact head, transition commit,
|
|
295
|
+
path, resulting blob and regular-file mode, or deletion tombstone. A strict-policy
|
|
296
|
+
migration also binds its old and new policy objects. A different attempt, commit, path
|
|
297
|
+
result, mode, or policy transition needs fresh authorization. A change not attributed to
|
|
298
|
+
the owner fails closed. This is owner authorization verified through GitHub attribution,
|
|
299
|
+
not independent review.
|
|
300
300
|
|
|
301
301
|
## Overrides
|
|
302
302
|
|
package/SECURITY.md
CHANGED
|
@@ -54,16 +54,14 @@ only the latest minor release will receive security fixes.
|
|
|
54
54
|
- A committed `.aimhooman.json` provides the versioned team profile. Invalid
|
|
55
55
|
project policy fails closed; per-clone allow/deny entries remain local and
|
|
56
56
|
should be governed by team process where compliance requires it.
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
reviewer. These checks verify GitHub attribution, not an interactive human action,
|
|
66
|
-
and cannot defend against malicious or compromised owner credentials.
|
|
57
|
+
- For protected-path changes (agent instruction files, `.aimhooman.json`), CI resolves
|
|
58
|
+
the repository and owner through the GitHub API and fetches the exact workflow-run
|
|
59
|
+
attempt. GitHub must attribute both the actor and triggering actor to the owner's
|
|
60
|
+
login and numeric ID. The resulting decision is bound to the exact head, transition
|
|
61
|
+
commit, path, blob, and regular-file mode (or deletion tombstone); a policy migration
|
|
62
|
+
also binds its old and new objects. Changes not attributed to the owner fail closed.
|
|
63
|
+
These checks verify GitHub actor attribution, not an interactive human action, and
|
|
64
|
+
cannot defend against a compromised owner credential.
|
|
67
65
|
- The release pipeline pins actions to immutable commit SHAs and publishes with npm
|
|
68
66
|
build provenance. Pushing a `v*` tag runs the workflow: it installs dependencies,
|
|
69
67
|
runs the test suite, then publishes to npm authenticated by the `NPM_TOKEN` secret
|