Skip to content
Open
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
21 changes: 21 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# dbdeployer-maintainer

## Project Identity
dbdeployer is a Go CLI for local MySQL, PostgreSQL, and ProxySQL sandboxes.

## Working Mode
- Follow TDD and keep changes minimal.
- Do not overwrite or revert work you did not make.
- Treat high-risk work under `cmd/`, `providers/`, `sandbox/`, `ops/`, `.github/workflows/`, `test/`, and `docs/` as correctness-sensitive.
- Use the project instructions/workflows `/dbdeployer-maintainer`, `/db-correctness-review`, `/verification-matrix`, and `/docs-reference-sync` when those assets are present in this setup.

## Verification Entry Points
- `go test ./...`
- `./test/go-unit-tests.sh`
- `./test/claude-agent-tests.sh`
- `.github/workflows/integration_tests.yml`
- `.github/workflows/proxysql_integration_tests.yml`

## Completion Contract
Final responses must include the sections `Changed`, `Verification`, `Edge Cases`, and `Docs Updated`.
Do not claim completion unless the required checks have been run and their results are known.
48 changes: 48 additions & 0 deletions .claude/hooks/block-destructive-commands.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# DBDeployer - The MySQL Sandbox
# Copyright © 2006-2020 Giuseppe Maxia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
Comment on lines +1 to +17
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add required copyright header to unblock CI.

The pipeline reports this file fails the sanity copyright check, so merge is currently blocked.

🧩 Minimal fix
 #!/usr/bin/env bash
+# Copyright (c) ProxySQL. All rights reserved.
 set -euo pipefail
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#!/usr/bin/env bash
set -euo pipefail
#!/usr/bin/env bash
# Copyright (c) ProxySQL. All rights reserved.
set -euo pipefail
🧰 Tools
🪛 GitHub Actions: CI

[error] 1-1: Sanity check failed (copyright). File has no copyright.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/hooks/block-destructive-commands.sh around lines 1 - 2, Add the
required copyright header as the first lines of the script before the shebang
(#!/usr/bin/env bash) so the CI copyright sanity check passes; insert the
organization's standard copyright/license block above the existing shebang and
keep the existing "set -euo pipefail" line intact.


input="$(cat)"
command="$(printf '%s' "$input" | jq -r '.tool_input.command // ""')"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The command string should be trimmed of leading and trailing whitespace before pattern matching. An agent might accidentally include a leading space (e.g., git reset --hard), which would bypass the block as currently implemented.

Suggested change
command="$(printf '%s' "$input" | jq -r '.tool_input.command // ""')"
command="$(printf '%s' "$input" | jq -r '.tool_input.command // ""' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"

normalized_command="$(printf '%s' "$command" | sed -E 's/^[[:space:]]+//')"

blocked_patterns=(
"git reset --hard"
"git checkout --"
"git clean -fd"
"git clean -ffd"
)

while [[ "$normalized_command" =~ ^[A-Za-z_][A-Za-z0-9_]*=[^[:space:]]+[[:space:]]+ ]]; do
normalized_command="${normalized_command#${BASH_REMATCH[0]}}"
normalized_command="$(printf '%s' "$normalized_command" | sed -E 's/^[[:space:]]+//')"
done

for pattern in "${blocked_patterns[@]}"; do
if [[ "$normalized_command" == "$pattern"* ]]; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Destructive git command blocked in dbdeployer. Use a non-destructive alternative."
}
}'
exit 0
fi
done

exit 0
45 changes: 45 additions & 0 deletions .claude/hooks/record-verification-command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
# DBDeployer - The MySQL Sandbox
# Copyright © 2006-2020 Giuseppe Maxia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail

input="$(cat)"
session_id="$(printf '%s' "$input" | jq -r '.session_id')"
cwd="$(printf '%s' "$input" | jq -r '.cwd')"
command="$(printf '%s' "$input" | jq -r '.tool_input.command // ""')"
project_dir="${CLAUDE_PROJECT_DIR:-$cwd}"
log_path="${CLAUDE_AGENT_VERIFICATION_LOG:-$project_dir/.claude/state/verification-log.jsonl}"
trimmed_command="$(printf '%s' "$command" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In addition to trimming leading and trailing whitespace, it is safer to normalize internal whitespace sequences to a single space. This ensures that commands like go test ./... (with multiple spaces) are correctly matched by the case statement.

Suggested change
trimmed_command="$(printf '%s' "$command" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
trimmed_command="$(printf '%s' "$command" | sed -E 's/[[:space:]]+/ /g; s/^ //; s/ $//')"


case "$trimmed_command" in
"go test ./..."|"go test ./... "*|\
"./test/go-unit-tests.sh"|"./test/go-unit-tests.sh "*|\
"./test/claude-agent-tests.sh"|"./test/claude-agent-tests.sh "*|\
"./test/functional-test.sh"|"./test/functional-test.sh "*|\
"./test/docker-test.sh"|"./test/docker-test.sh "*|\
"./test/proxysql-integration-tests.sh"|"./test/proxysql-integration-tests.sh "*|\
"./scripts/build.sh"|"./scripts/build.sh "*)
mkdir -p "$(dirname "$log_path")"
jq -cn \
--arg session_id "$session_id" \
--arg cwd "$cwd" \
--arg command "$trimmed_command" \
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'{session_id: $session_id, cwd: $cwd, command: $command, timestamp: $timestamp}' >> "$log_path"
;;
Comment on lines +19 to +42
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hook records verification commands purely based on the command string, without checking whether the command succeeded. As a result, a failed go test ./... run would still be logged and could satisfy the Stop completion gate. If the PostToolUse payload provides an exit status / error flag, use it to only log successful runs (or otherwise rename the behavior/docs to avoid claiming “successful verification”).

Copilot uses AI. Check for mistakes.
esac

exit 0
126 changes: 126 additions & 0 deletions .claude/hooks/stop-completion-gate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/env bash
# DBDeployer - The MySQL Sandbox
# Copyright © 2006-2020 Giuseppe Maxia
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail

input="$(cat)"
session_id="$(printf '%s' "$input" | jq -r '.session_id')"
cwd="$(printf '%s' "$input" | jq -r '.cwd')"
message="$(printf '%s' "$input" | jq -r '.last_assistant_message // ""')"
stop_hook_active="$(printf '%s' "$input" | jq -r '.stop_hook_active // false')"
project_dir="${CLAUDE_PROJECT_DIR:-$cwd}"
log_path="${CLAUDE_AGENT_VERIFICATION_LOG:-$project_dir/.claude/state/verification-log.jsonl}"
changed_files="${CLAUDE_AGENT_CHANGED_FILES:-}"

requires_claude_verification=0
requires_go_verification=0
requires_docs=0
docs_updated=0
saw_changed_file=0

classify_changed_file() {
local file="$1"

[[ -z "$file" ]] && return 0

saw_changed_file=1

if [[ "$file" =~ ^(\.claude/|test/claude-agent/|test/claude-agent-tests\.sh$|tools/claude-skills/db-core-expertise/|scripts/install_claude_db_skills\.sh$) ]]; then
requires_claude_verification=1
elif [[ "$file" =~ ^(common/|cmd/|ops/|providers/|sandbox/|test/|\.github/workflows/) ]]; then
requires_go_verification=1
fi

if [[ "$file" =~ ^(cmd/|providers/|sandbox/|ops/|common/) ]]; then
requires_docs=1
fi

if [[ "$file" =~ ^(docs/|README\.md|CONTRIBUTING\.md|\.claude/CLAUDE\.md|\.claude/rules/) ]]; then
docs_updated=1
fi
}

has_logged_command() {
local expected_command="$1"

[[ -f "$log_path" ]] || return 1

jq -s -e \
--arg session_id "$session_id" \
--arg expected_command "$expected_command" \
'
map(
select(
.session_id == $session_id and (
.command == $expected_command or
(.command | startswith($expected_command + " "))
)
)
) | length > 0
' "$log_path" >/dev/null 2>&1
}

if [[ "$stop_hook_active" == "true" ]]; then
exit 0
fi

if [[ -n "$changed_files" ]]; then
while IFS= read -r file; do
classify_changed_file "$file"
done <<< "$changed_files"
else
while IFS= read -r file; do
classify_changed_file "$file"
done < <(git -C "$project_dir" diff --name-only -M HEAD --)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using git diff without the -z flag and reading it with a standard while read loop is fragile if filenames contain special characters like newlines. For robustness and consistency with the ls-files call on line 76, use the -z flag and a null-delimited read loop.

Suggested change
done < <(git -C "$project_dir" diff --name-only -M HEAD --)
while IFS= read -r -d '' file; do
classify_changed_file "$file"
done < <(git -C "$project_dir" diff --name-only -z -M HEAD --)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The fallback logic using git diff --name-only HEAD only identifies uncommitted changes. If the agent has already committed its work during the session, this check will return an empty list, effectively bypassing the verification and documentation gates. While CLAUDE_AGENT_CHANGED_FILES is checked first, the fallback should ideally account for committed changes in the current branch if possible.


while IFS= read -r -d '' file; do
classify_changed_file "$file"
done < <(git -C "$project_dir" ls-files --others --exclude-standard -z)
fi

if [[ "$saw_changed_file" -eq 0 ]]; then
exit 0
fi

missing_verification=()

if [[ "$requires_claude_verification" -eq 1 ]] && ! has_logged_command "./test/claude-agent-tests.sh"; then
missing_verification+=("./test/claude-agent-tests.sh")
fi

if [[ "$requires_go_verification" -eq 1 ]] && ! has_logged_command "go test ./..." && ! has_logged_command "./test/go-unit-tests.sh"; then
missing_verification+=("go test ./... or ./test/go-unit-tests.sh")
Comment on lines +104 to +105
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Go verification gate currently passes if either go test ./... or ./test/go-unit-tests.sh was logged. However, .claude/rules/testing-and-completion.md states Go code changes must be checked with both commands. Either tighten the gate to require both (when requires_go_verification=1) or relax/update the rule so policy and enforcement are consistent.

Suggested change
if [[ "$requires_go_verification" -eq 1 ]] && ! has_logged_command "go test ./..." && ! has_logged_command "./test/go-unit-tests.sh"; then
missing_verification+=("go test ./... or ./test/go-unit-tests.sh")
if [[ "$requires_go_verification" -eq 1 ]]; then
if ! has_logged_command "go test ./..."; then
missing_verification+=("go test ./...")
fi
if ! has_logged_command "./test/go-unit-tests.sh"; then
missing_verification+=("./test/go-unit-tests.sh")
fi

Copilot uses AI. Check for mistakes.
fi

if [[ "${#missing_verification[@]}" -gt 0 ]]; then
reason_suffix="${missing_verification[*]}"
jq -n --arg reason "Run the required verification before finishing. Missing a successful command for: $reason_suffix." '{decision: "block", reason: $reason}'
exit 0
fi

if [[ "$requires_docs" -eq 1 && "$docs_updated" -eq 0 ]]; then
jq -n --arg reason "Behavior-sensitive files changed without a docs update. Add the relevant docs update before finishing." '{decision: "block", reason: $reason}'
exit 0
fi

for section in "Changed" "Verification" "Edge Cases" "Docs Updated"; do
if [[ "$message" != *"$section"* ]]; then
jq -n --arg reason "Final response must include '$section' so completion is auditable." '{decision: "block", reason: $reason}'
exit 0
fi
done

exit 0
18 changes: 18 additions & 0 deletions .claude/rules/provider-surfaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
paths:
- cmd/**/*
- providers/**/*
- sandbox/**/*
- ops/**/*
- docs/**/*
- .github/workflows/**/*
---

## Provider Surface Guidance
Review MySQL, PostgreSQL, and ProxySQL behavior as correctness-sensitive.

Check for version differences, package layout assumptions, startup ordering, auth defaults, port allocation, and replication semantics before changing behavior.

For ProxySQL work, verify the admin port and MySQL port pairing and make sure configuration changes preserve the intended routing behavior.

When behavior changes, update the relevant docs in `docs/`, `README.md`, and `CONTRIBUTING.md` alongside the code.
21 changes: 21 additions & 0 deletions .claude/rules/testing-and-completion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Verification-Sensitive Paths
Treat these paths as verification-sensitive:
- `cmd/`
- `providers/`
- `sandbox/`
- `ops/`
- `common/`
- `test/`
- `.github/workflows/`
- `.claude/`
- `tools/claude-skills/db-core-expertise/`
- `scripts/install_claude_db_skills.sh`

## Required Checks
- Changes under `.claude/**`, `tools/claude-skills/db-core-expertise/**`, and `scripts/install_claude_db_skills.sh` must be checked with `./test/claude-agent-tests.sh`.
- Go code changes must be checked with either `go test ./...` or `./test/go-unit-tests.sh`.
- Workflow-related changes must stay aligned with the matching jobs in `.github/workflows/integration_tests.yml` and `.github/workflows/proxysql_integration_tests.yml`.

## Completion Language
Final responses must include the sections `Changed`, `Verification`, `Edge Cases`, and `Docs Updated`.
If required checks cannot run, the task must not be described as complete.
37 changes: 37 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(*git *)",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-destructive-commands.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/record-verification-command.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/stop-completion-gate.sh"
}
]
}
]
}
}
23 changes: 23 additions & 0 deletions .claude/skills/db-correctness-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: db-correctness-review
description: Adversarial MySQL/PostgreSQL/ProxySQL review for dbdeployer changes.
disable-model-invocation: true
---

# db correctness review

Invoke `/db-core-expertise` first if it is available, then review the change for database correctness.

## Checklist

- Database semantics
- Lifecycle behavior
- Packaging and environment assumptions
- Topology and routing behavior
- Operator edge cases

## Findings format

- Correctness Risks
- Edge Cases Checked
- Recommended Follow-up
26 changes: 26 additions & 0 deletions .claude/skills/dbdeployer-maintainer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: dbdeployer-maintainer
description: Primary maintainer workflow for dbdeployer; use for non-trivial feature work, bug fixes, provider changes, verification tasks, or docs sync.
---

# dbdeployer maintainer workflow

Use this when the task can change behavior, provider support, verification, or reference docs.

## Sequence

1. Frame the task and restate the expected change surface.
2. Implement or investigate the requested change.
3. If `/db-core-expertise` is available, invoke it for MySQL, PostgreSQL, or ProxySQL questions before concluding.
4. If database behavior may have changed, invoke `/db-correctness-review`.
5. If behavior, flags, support statements, or examples changed, invoke `/docs-reference-sync`.
6. Before stopping, invoke `/verification-matrix` and use its strongest applicable checks.

## Final response

Close with these sections:

- Changed
- Verification
- Edge Cases
- Docs Updated
22 changes: 22 additions & 0 deletions .claude/skills/docs-reference-sync/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: docs-reference-sync
description: Syncs docs and reference material after dbdeployer behavior, flags, support statements, or examples change.
disable-model-invocation: true
---

# docs reference sync

## Workflow

1. List the changed doc surfaces, especially `docs/`, `README.md`, and `CONTRIBUTING.md`.
2. Update the smallest truthful set of files.
3. Prefer concrete commands and caveats over broad prose.
4. State limitations directly.

## Supplemental Output

These fields are supplemental only. They must not replace the required final response sections `Changed`, `Verification`, `Edge Cases`, and `Docs Updated` defined in `.claude/CLAUDE.md` and enforced by `test/claude-agent-tests.sh`.

- Docs To Update
- Files Updated
- Open Caveats
Loading
Loading