Skip to content

Commit d08705c

Browse files
committed
chore(git): sync attribution guard scripts and cursor rules
1 parent 15f176d commit d08705c

22 files changed

Lines changed: 1371 additions & 0 deletions
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
description: Load gitignored private attribution lessons before any git commit
3+
alwaysApply: true
4+
---
5+
6+
# Private attribution (never publish tokens)
7+
8+
Before `git commit` or `git push`:
9+
10+
1. Read **`.cursor/private/agent-lesson-git-attribution.md`** (gitignored — not on GitHub).
11+
2. Read **`.cursor/private/banned-attribution-patterns`** for the live token list.
12+
3. If missing: `bash scripts/cursor/install-user-git-environment.sh` (pulls from orama + sync).
13+
4. **Never** copy banned tokens into tracked files, commit messages, PR text, or LESSONS.
14+
15+
Public policy (no token examples): `../orama-system/docs/wiki/08-git-hygiene-and-branching.md`
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
description: Re-introducing expunged commit attribution forces destructive main rewrites — never do it
3+
alwaysApply: true
4+
---
5+
6+
# Attribution expunge is fragile — do not undo it
7+
8+
## The loop you must break
9+
10+
Every time an agent adds **forbidden** `Co-authored-by` trailers (listed in `.cursor/private/banned-attribution-patterns`, never on GitHub), the owner must:
11+
12+
1. Rewrite history (`bash scripts/git/expunge-all-workspace-repos.sh` or per-repo expunge)
13+
2. Force-push **`main` and every branch** again
14+
15+
That is destructive for all collaborators. **Do not cause another rewrite.**
16+
17+
## Non-negotiable agent behavior
18+
19+
| Do | Do not |
20+
|----|--------|
21+
| Read `.cursor/private/agent-lesson-git-attribution.md` before any git write | Copy forbidden tokens into tracked files, commits, PRs, or LESSONS |
22+
| Commit with `bash scripts/git/commit-clean.sh -m "..."` after `git add` | Raw `git commit` in Cursor cloud |
23+
| Push with `bash scripts/git/publish-clean-branch.sh <branch> main origin` | Raw `git push` without audit |
24+
| Run `bash scripts/git/daily-attribution-guard.sh` at session start | "Document" forbidden emails in repo docs so you remember |
25+
26+
## Session checklist (every day)
27+
28+
```bash
29+
bash scripts/git/daily-attribution-guard.sh
30+
bash scripts/git/install-local-hooks.sh
31+
```
32+
33+
If CI or scan fails: fix before any new commits. Never patch by echoing forbidden identities in commit messages.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
description: Never add Cursor or third-party co-author trailers to git commits
3+
alwaysApply: true
4+
---
5+
6+
# Git commit attribution (cloud + agent)
7+
8+
When committing in this repository:
9+
10+
1. **Never** add `Co-authored-by:`, `Made-with: Cursor`, or any Cursor/agent attribution trailer to commit messages.
11+
2. **Cursor cloud** installs guards automatically: `bash scripts/cursor/install-user-git-environment.sh` (also via `.cursor/environment.json` → `cloud-bootstrap.sh` on VM start).
12+
3. **Every clone** must run `bash scripts/git/install-local-hooks.sh` (enforced by pre-commit + CI).
13+
4. Use only approved **author** identity: `cyre <Lawrence@cyre.me>` or `cyre <diazMelgarejo@gmail.com>` (or `Codex <codex@openai.com>`). Never `Cursor Agent` as author.
14+
5. **Before every push:** `pre-push` runs attribution audit — banned `Co-authored-by` never reaches GitHub.
15+
6. To publish: `bash scripts/git/publish-clean-branch.sh <branch>` (neutralize → verify → audit → push).
16+
7. **Banned identities:** read `.cursor/private/agent-lesson-git-attribution.md` (gitignored).
17+
Do not echo banned tokens in tracked docs. Use `bash scripts/git/commit-clean.sh` if Cursor injects trailers.
18+
8. **Never** `git push` without hooks installed (`bash scripts/git/install-local-hooks.sh`).
19+
20+
Desktop (optional): Cursor Settings → Agents → Attribution → OFF (IDE/CLI only; cloud may still inject until guards run).
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
description: Banned identities must not appear in code, commits, authors, or messages — ever on GitHub
3+
alwaysApply: true
4+
---
5+
6+
# Zero tolerance (four layers)
7+
8+
Forbidden identities are listed only in `.cursor/private/banned-attribution-patterns` (gitignored).
9+
10+
They must not appear in:
11+
12+
1. **Tracked code or docs** — CI runs `bash scripts/git/scan-tracked-banned-tokens.sh`
13+
2. **Commit author or committer** — `check_identity.sh` + `audit_attribution.sh`
14+
3. **Commit message body** (including `Co-authored-by`) — strip hook + `check_commit_message.sh` + `commit-clean.sh`
15+
4. **GitHub at all** — `pre-push` audit; if leaked, run `expunge-all-workspace-repos.sh` and force-push every branch
16+
17+
Re-adding after an expunge forces another destructive `main` rewrite. Do not document forbidden tokens in the repo to "remember" them — read `.cursor/private/agent-lesson-git-attribution.md` only.

AGENTS.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,22 @@ handle data version changes. Schema changes use ALTER TABLE; parser changes
190190
trigger a full resync (build fresh DB, sync files, copy orphaned sessions from
191191
old DB, atomic swap). Existing session data must be preserved even when source
192192
files no longer exist on disk.
193+
194+
## Cursor Cloud: git commits
195+
196+
Run on cloud VM boot:
197+
198+
```bash
199+
bash scripts/git/apply-attribution-guard-all-repos.sh
200+
```
201+
202+
Hook-free commit when needed:
203+
204+
```bash
205+
bash scripts/git/commit-clean.sh -m "type(scope): summary"
206+
```
207+
208+
See orama-system `docs/wiki/09-cursor-cloud-commit-attribution.md` (canonical).
209+
210+
**Fork policy:** integration branch is `merged`. Open agent PRs from
211+
`cursor/*` branches → `merged` (never → `main`).
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env bash
2+
# Apply mandatory git hooks to Perpetua-Tools + sibling repos (Cursor session + manual).
3+
set -euo pipefail
4+
5+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6+
PT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
7+
DISABLE="$SCRIPT_DIR/disable-cursor-commit-attribution.sh"
8+
INSTALL="$SCRIPT_DIR/install-local-hooks.sh"
9+
SYNC="$SCRIPT_DIR/sync-attribution-guard-scripts.sh"
10+
11+
OPENCLAW_HOME="${OPENCLAW_HOME:-$HOME/openclaw-v1}"
12+
13+
resolve_git_repo() {
14+
local r="$1"
15+
[[ -n "$r" ]] || return 1
16+
[[ "$r" == *'${'* ]] && return 1
17+
[[ -d "$r/.git" ]] || return 1
18+
local abs
19+
abs="$(cd "$r" && pwd)" || return 1
20+
printf '%s' "$abs"
21+
}
22+
23+
raw_candidates=(
24+
"$PT_ROOT"
25+
"${PERPETUA_TOOLS_PATH:-$PT_ROOT}"
26+
"${PERPETUA_TOOLS_ROOT:-$PT_ROOT}"
27+
"${ORAMA_SYSTEM_PATH:-$OPENCLAW_HOME/orama-system}"
28+
"${ALPHACLAW_INSTALL_DIR:-$OPENCLAW_HOME/AlphaClaw}"
29+
"/agent/repos/Perpetua-Tools"
30+
"/agent/repos/orama-system"
31+
"/agent/repos/AlphaClaw"
32+
"/agent/repos/periscope"
33+
)
34+
35+
if [[ -d /agent/repos ]]; then
36+
for d in /agent/repos/*; do
37+
raw_candidates+=("$d")
38+
done
39+
fi
40+
41+
declare -A seen=()
42+
unique=()
43+
for r in "${raw_candidates[@]}"; do
44+
resolved="$(resolve_git_repo "$r" 2>/dev/null || true)"
45+
[[ -n "$resolved" ]] || continue
46+
if [[ -n "${seen[$resolved]+x}" ]]; then
47+
continue
48+
fi
49+
seen[$resolved]=1
50+
unique+=("$resolved")
51+
done
52+
53+
if [[ -x "$SYNC" ]]; then
54+
for r in "${unique[@]}"; do
55+
[[ "$r" == "$PT_ROOT" ]] && continue
56+
bash "$SYNC" "$r" 2>/dev/null || true
57+
done
58+
fi
59+
60+
for r in "${unique[@]}"; do
61+
bash "$DISABLE" "$r"
62+
if [[ -x "$INSTALL" && -x "$r/scripts/git/ensure_hooks_installed.sh" ]]; then
63+
bash "$INSTALL" "$r" || echo "warn: install-local-hooks failed: $r" >&2
64+
elif [[ -x "$DISABLE" ]]; then
65+
:
66+
fi
67+
git -C "$r" config --local user.name "cyre" 2>/dev/null || true
68+
git -C "$r" config --local user.email "Lawrence@cyre.me" 2>/dev/null || true
69+
done
70+
71+
echo "OK: mandatory hooks applied for ${#unique[@]} repo(s)"

scripts/git/audit_attribution.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
# Scan commits for Co-authored-by policy, non-approved authors, and banned attribution.
3+
set -euo pipefail
4+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
6+
N="${1:-79}"
7+
exec python3 "$SCRIPT_DIR/audit_engine.py" audit \
8+
--repo "$REPO_ROOT" \
9+
--history-count "$N"
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#!/usr/bin/env bash
2+
# Shared helpers for gitignored banned-attribution patterns (no literals in callers).
3+
set -euo pipefail
4+
5+
banned_patterns_file() {
6+
local root="${1:-}"
7+
if [[ -z "$root" ]]; then
8+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
9+
fi
10+
local private="${root}/.cursor/private/banned-attribution-patterns"
11+
if [[ -f "$private" && -s "$private" ]]; then
12+
printf '%s' "$private"
13+
return 0
14+
fi
15+
local openclaw="${OPENCLAW_ATTRIBUTION_PATTERNS:-${HOME:-}/.cursor/openclaw/banned-attribution-patterns}"
16+
if [[ -f "$openclaw" && -s "$openclaw" ]]; then
17+
printf '%s' "$openclaw"
18+
return 0
19+
fi
20+
printf '%s' "$private"
21+
}
22+
23+
# banned_patterns_ready reports whether a valid banned-attribution patterns file exists and is non-empty.
24+
# banned_patterns_ready accepts an optional root directory argument used to resolve the patterns file; it exits with status 0 if the resolved file exists and has size > 0, non-zero otherwise.
25+
banned_patterns_ready() {
26+
local f
27+
f="$(banned_patterns_file "${1:-}")"
28+
[[ -f "$f" && -s "$f" ]]
29+
}
30+
31+
# list_banned_pattern_tokens streams banned-attribution pattern tokens (one per line) from the repository or user patterns file.
32+
# It resolves the patterns file (optional `root` argument), reads it line-by-line, removes inline comments (`#`) and all whitespace, skips empty tokens, and writes each remaining token to stdout on its own line.
33+
# Usage: while read -r token; do ...; done < <(list_banned_pattern_tokens "$root")
34+
# Parameters:
35+
# root (optional) — repository root directory to use when resolving the patterns file; if omitted, the script determines the root automatically.
36+
# Exit:
37+
# Returns non-zero if the resolved patterns file does not exist or cannot be read.
38+
list_banned_pattern_tokens() {
39+
local f token
40+
f="$(banned_patterns_file "${1:-}")"
41+
if [[ ! -f "$f" ]]; then
42+
return 1
43+
fi
44+
while IFS= read -r token || [[ -n "$token" ]]; do
45+
token="${token%%#*}"
46+
token="$(printf '%s' "$token" | tr -d '[:space:]')"
47+
[[ -n "$token" ]] || continue
48+
printf '%s\n' "$token"
49+
done <"$f"
50+
}
51+
52+
# first_banned_pattern_token outputs the first non-empty, non-comment banned-attribution pattern token from the resolved patterns file (takes an optional root directory argument).
53+
# It prints the token to stdout and returns success; if no file or no token is found it returns a non-zero status.
54+
first_banned_pattern_token() {
55+
local f token
56+
f="$(banned_patterns_file "${1:-}")"
57+
if [[ ! -f "$f" ]]; then
58+
return 1
59+
fi
60+
while IFS= read -r token || [[ -n "$token" ]]; do
61+
token="${token%%#*}"
62+
token="$(printf '%s' "$token" | tr -d '[:space:]')"
63+
[[ -n "$token" ]] || continue
64+
printf '%s' "$token"
65+
return 0
66+
done <"$f"
67+
return 1
68+
}
69+
70+
# line_matches_banned_pattern checks whether a lowercased line contains any banned-attribution pattern token; tokens are lowercased before matching and are read from the resolved patterns file.
71+
line_matches_banned_pattern() {
72+
local line_lc="$1"
73+
local root="${2:-}"
74+
local token token_lc
75+
while IFS= read -r token; do
76+
token_lc="$(printf '%s' "$token" | tr '[:upper:]' '[:lower:]')"
77+
if [[ "$line_lc" == *"$token_lc"* ]]; then
78+
return 0
79+
fi
80+
done < <(list_banned_pattern_tokens "$root" 2>/dev/null || true)
81+
return 1
82+
}
83+
84+
openclaw_workspace_root() {
85+
local root="${1:-}"
86+
if [[ -z "$root" ]]; then
87+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
88+
fi
89+
local cur="$root"
90+
while [[ "$cur" != "/" && -n "$cur" ]]; do
91+
if [[ -d "$cur/orama-system" ]]; then
92+
printf '%s' "$cur"
93+
return 0
94+
fi
95+
cur="$(dirname "$cur")"
96+
done
97+
printf '%s' "$root"
98+
}
99+
100+
verboten_literals_file() {
101+
local root="${1:-}"
102+
if [[ -n "${OPENCLAW_VERBOTEN_LITERALS:-}" ]]; then
103+
printf '%s' "$OPENCLAW_VERBOTEN_LITERALS"
104+
return 0
105+
fi
106+
printf '%s/.verboten-literals.local' "$(openclaw_workspace_root "$root")"
107+
}
108+
109+
list_private_literal_values() {
110+
local root="${1:-}" selector="${2:-}" f raw key value
111+
f="$(verboten_literals_file "$root")"
112+
[[ -f "$f" ]] || return 1
113+
while IFS= read -r raw || [[ -n "$raw" ]]; do
114+
raw="${raw%%#*}"
115+
raw="$(printf '%s' "$raw" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
116+
[[ -n "$raw" ]] || continue
117+
case "$raw" in
118+
*=*)
119+
key="${raw%%=*}"
120+
value="${raw#"$key="}"
121+
value="$(printf '%s' "$value" | tr -d '[:space:]')"
122+
[[ -n "$value" ]] || continue
123+
[[ -z "$selector" || "$key" == "$selector" ]] || continue
124+
printf '%s\n' "$value"
125+
;;
126+
esac
127+
done <"$f"
128+
}
129+
130+
private_owner_email_ok() {
131+
local email_lc="$1" root="${2:-}" token token_lc
132+
while IFS= read -r token; do
133+
token_lc="$(printf '%s' "$token" | tr '[:upper:]' '[:lower:]')"
134+
[[ "$email_lc" == "$token_lc" ]] && return 0
135+
done < <(list_private_literal_values "$root" owner_gmail 2>/dev/null || true)
136+
return 1
137+
}
138+
139+
private_owner_name_ok() {
140+
local name_lc="$1" root="${2:-}" token token_lc
141+
while IFS= read -r token; do
142+
token_lc="$(printf '%s' "$token" | tr '[:upper:]' '[:lower:]')"
143+
[[ "$name_lc" == *"$token_lc"* ]] && return 0
144+
done < <(list_private_literal_values "$root" owner_name 2>/dev/null || true)
145+
return 1
146+
}
147+
148+
line_matches_private_forbidden_literal() {
149+
local line_lc="$1" root="${2:-}" token token_lc
150+
while IFS= read -r token; do
151+
token_lc="$(printf '%s' "$token" | tr '[:upper:]' '[:lower:]')"
152+
[[ "$line_lc" == *"$token_lc"* ]] && return 0
153+
done < <(list_private_literal_values "$root" forbidden_attribution 2>/dev/null || true)
154+
return 1
155+
}
156+
157+
# banned_attribution_hit returns 0 when author/committer/body metadata matches a banned pattern.
158+
banned_attribution_hit() {
159+
local ae_lc="$1" an_lc="$2" ce_lc="$3" cn_lc="$4" body_lc="$5"
160+
local root="${6:-}"
161+
if ! banned_patterns_ready "$root"; then
162+
return 1
163+
fi
164+
line_matches_banned_pattern "$ae_lc" "$root" && return 0
165+
line_matches_private_forbidden_literal "$ae_lc" "$root" && return 0
166+
line_matches_banned_pattern "$an_lc" "$root" && return 0
167+
line_matches_private_forbidden_literal "$an_lc" "$root" && return 0
168+
line_matches_banned_pattern "$ce_lc" "$root" && return 0
169+
line_matches_private_forbidden_literal "$ce_lc" "$root" && return 0
170+
line_matches_banned_pattern "$cn_lc" "$root" && return 0
171+
line_matches_private_forbidden_literal "$cn_lc" "$root" && return 0
172+
local line line_lc
173+
while IFS= read -r line; do
174+
line_lc="$(printf '%s' "$line" | tr '[:upper:]' '[:lower:]')"
175+
case "$line_lc" in
176+
co-authored-by:*)
177+
if line_matches_banned_pattern "$line_lc" "$root"; then
178+
return 0
179+
fi
180+
if line_matches_private_forbidden_literal "$line_lc" "$root"; then
181+
return 0
182+
fi
183+
;;
184+
esac
185+
done <<< "$body_lc"
186+
return 1
187+
}

0 commit comments

Comments
 (0)