Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/guidelines
1 change: 1 addition & 0 deletions .agents/project.md
1 change: 1 addition & 0 deletions .agents/scripts
1 change: 1 addition & 0 deletions .agents/shared
Submodule shared added at 2369ab
1 change: 1 addition & 0 deletions .agents/skills
1 change: 1 addition & 0 deletions .claude/agents
1 change: 1 addition & 0 deletions .claude/commands
106 changes: 106 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"plansDirectory": ".claude/plans",
"permissions": {
"allow": [
"Edit(version.gradle.kts)",
"Bash(./gradlew:*)",
"Bash(./config/gradlew:*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git show:*)",
"Bash(git branch:*)",
"Bash(git switch:*)",
"Bash(git checkout:*)",
"Bash(git add:*)",
"Bash(git restore:*)",
"Bash(git stash:*)",
"Bash(git fetch:*)",
"Bash(git push:*)",
"Bash(git rev-parse:*)",
"Bash(git ls-files:*)",
"Bash(git mv:*)",
"Bash(git submodule status:*)",
"Bash(ls:*)",
"Bash(cat:*)",
"Bash(head:*)",
"Bash(tail:*)",
"Bash(wc:*)",
"Bash(find:*)",
"Bash(rg:*)",
"Bash(grep:*)",
"Bash(mkdir:*)",
"Bash(touch:*)",
"Bash(python3 .agents/skills/update-copyright/scripts/update_copyright.py:*)",
"Bash(.agents/skills/version-bumped/scripts/version-bumped.sh)",
"Bash(./config/pull)",
"Bash(./config/migrate)",
"Skill(pre-pr)",
"Skill(pre-pr:*)"
],
"deny": [
"Bash(git reset --hard:*)",
"Bash(git clean -fdx:*)",
"Bash(rm -rf /:*)",
"Bash(rm -rf ~:*)",
"Bash(gh pr merge:*)",
"Bash(gh release create:*)"
],
"ask": [
"Bash(git commit:*)",
"Bash(git rebase:*)",
"Bash(git merge:*)",
"Bash(git cherry-pick:*)",
"Bash(./gradlew publish:*)",
"Bash(./gradlew uploadArtifacts:*)",
"Bash(./gradlew clean:*)"
]
},
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/init-submodules"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.agents/scripts/secret-scan-gate.sh"
},
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.agents/scripts/pre-pr-gate.sh"
},
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.agents/scripts/publish-version-gate.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.agents/scripts/sanitize-source-code.sh"
},
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.agents/scripts/update-copyright.sh"
}
]
}
]
}
}
1 change: 1 addition & 0 deletions .claude/skills
66 changes: 66 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto

# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.

# Common formats
*.html text
*.xml text
*.css text
*.scss text
*.svg text
*.js text
*.properties text
*.rtf text
*.yaml text
*.yml text
*.md text

LICENSE text

# SQL scripts
*.sql text

# Java sources
*.java text

# Kotlin sources
*.kt text
*.kts text

# Python sources
*.py text

# Gradle build files
*.gradle text

# Google protocol buffers
*.proto text

# Miscellaneous
*.rb text

# Declare files that will always have CRLF line endings on checkout.
*.bat text eol=crlf

# Declare files that will always have LF line endings on checkout.
*.sh text eol=lf
gradlew text eol=lf
pull text eol=lf

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.gif binary
*.swf binary
*.jar binary
*.desc binary

*.scpt binary
*.scssc binary

# Encrypted files
*.enc binary
*.gpg binary
*.weis binary
45 changes: 45 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# GitHub Copilot Instructions

## Repository context

This repository is part of the Spine SDK organisation (~40 repos).

Universal agent instructions are in [`AGENTS.md`](../AGENTS.md) at the
repository root — read it first.

If `.agents/project.md` exists, read it before reviewing. It provides the
language, architecture, role, and code review checklist for this specific repo.

Additional guidelines are in `.agents/guidelines/` — see
`.agents/guidelines/_TOC.md` for the index.

## Do not review

Never review `gradlew` or `gradlew.bat` in any repository, including `config`.
These files are provided by Gradle and are not edited manually.

If the current repository is `config`, review its files normally unless noted
above: they are authoritative there. In other repositories, the following files are managed by
the `config` submodule and must be reviewed in the `config` repository, not
here. In those consumer repositories, skip them without comment:

- `AGENTS.md`, `CLAUDE.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`
- `.agents/**` (except `.agents/project.md`)
- `.claude/**`, `.idea/**`, `.junie/**`
- `.github/copilot-instructions.md`
- `buildSrc/**` (except `buildSrc/src/main/kotlin/module.gradle.kts`)
- `gradle/`, `gradlew`, `gradlew.bat`
- `.codecov.yml`, `.gitignore`, `gradle.properties`, `lychee.toml`
- `.github/workflows/` — unless the workflow was introduced by this repo

## Universal rules

**Do not suggest:**
- Any git history operation — `git commit`, `git push`, `git tag`,
`git rebase`, `git merge`, `git cherry-pick`, `gh pr merge`, or any other
command that writes to history — leave these to the developer.
- Auto-updating dependency versions outside a dedicated update task.
- Feature flags, backwards-compatibility shims, or fallbacks for scenarios
that cannot occur in the current codebase.
- Analytics, telemetry, or tracking code.
- Reflection or unsafe code without explicit approval.
70 changes: 70 additions & 0 deletions .github/workflows/secret-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Secret scan

# Defense-in-depth behind the local `secret-scan` pre-commit hook and the
# `.gitignore` secret patterns: if a credential is committed despite those, this
# fails the pull request before it can merge. Distributed to every Spine repo by
# `./config/pull`.

on:
pull_request:
push:
branches:
- master
- main

permissions:
contents: read

jobs:
gitleaks:
name: gitleaks
runs-on: ubuntu-latest
env:
# Pinned gitleaks version — bump through the usual dependency-update process.
GITLEAKS_VERSION: "8.21.2"
steps:
- name: Checkout
uses: actions/checkout@v6
with:
# Full history so a pull request's commit range can be scanned.
fetch-depth: 0

- name: Install gitleaks
# Run gitleaks as the runner user against the checkout it owns — no
# container, so no "dubious ownership" git error and no GitHub Action
# org-licence requirement.
run: |
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| tar -xzf - gitleaks
./gitleaks version

- name: Scan
env:
EVENT: ${{ github.event_name }}
BASE: ${{ github.event.pull_request.base.sha }}
HEAD: ${{ github.event.pull_request.head.sha }}
BEFORE: ${{ github.event.before }}
AFTER: ${{ github.sha }}
run: |
if [ "$EVENT" = pull_request ]; then
# Scan the PR's own commit RANGE: a secret added in one commit and
# deleted in a later commit of the same PR is still caught (a
# working-tree scan would miss it, yet merging keeps the secret-bearing
# commit reachable), while already-rotated secrets in older history
# outside base..head are not re-flagged.
./gitleaks git --log-opts="$BASE..$HEAD" --redact --verbose --exit-code=1 .
else
# Push to a default branch: scan the pushed commit RANGE (before..after)
# so an add-then-remove batch is caught here too, not only on PRs — the
# leaked commit would otherwise stay reachable on the default branch. A
# branch's first push reports an all-zero `before` (no range); fall back
# to a working-tree scan then.
if [ -n "$BEFORE" ] && [ "$BEFORE" != "0000000000000000000000000000000000000000" ]; then
./gitleaks git --log-opts="$BEFORE..$AFTER" --redact --verbose --exit-code=1 .
else
# Branch's first push (all-zero `before`): no range to diff against, so
# scan the whole history reachable from the pushed tip as the initial
# import — an add-then-remove within those commits is still caught.
./gitleaks git --log-opts="$AFTER" --redact --verbose --exit-code=1 .
fi
fi
Loading