fix(permission-gate): guard release-* branch and v* tag pushes (deploy convention)
Deploy convention at M.Video: a release-* branch push deploys to stage and a v* tag push deploys to PROD. The old guard only matched release/* (slash) and never caught tag pushes, so a prod deploy could run unconfirmed. - permission-gate: match main/master, release-[-/], --tags/--follow-tags, and whitespace-preceded v<digit> tags; false-positive-safe (space discriminator) - create-mr.sh: refuse source branch release-* (not just release/*) - jira-workflow doc updated to release-* Verified with a behavioral test suite (10 cases incl. v2, false-positive checks).
This commit is contained in:
@@ -22,10 +22,12 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|||||||
const DANGEROUS_PATTERNS: Array<{ re: RegExp; reason: string }> = [
|
const DANGEROUS_PATTERNS: Array<{ re: RegExp; reason: string }> = [
|
||||||
{ re: /\brm\s+(-\w*r\w*f|-\w*f\w*r|--recursive)/i, reason: "recursive force delete (rm -rf)" },
|
{ re: /\brm\s+(-\w*r\w*f|-\w*f\w*r|--recursive)/i, reason: "recursive force delete (rm -rf)" },
|
||||||
{ re: /\bgit\s+push\b[^\n]*(--force\b|--force-with-lease\b|\s-f\b)/i, reason: "force push" },
|
{ re: /\bgit\s+push\b[^\n]*(--force\b|--force-with-lease\b|\s-f\b)/i, reason: "force push" },
|
||||||
{
|
{ re: /\bgit\s+push\b[^\n]*\b(main|master)\b/i, reason: "push to main/master" },
|
||||||
re: /\bgit\s+push\b[^\n]*\b(main|master|release\/[^\s]+)\b/i,
|
// Deploy convention: a `release-*` branch push deploys to STAGE, and a `v*`
|
||||||
reason: "push to a protected branch (main/master/release/*)",
|
// tag push deploys to PROD. Guard both the branch and the tag pushes.
|
||||||
},
|
{ re: /\bgit\s+push\b[^\n]*\brelease[-/]\S+/i, reason: "push to a release-* branch (deploys to stage)" },
|
||||||
|
{ re: /\bgit\s+push\b[^\n]*(--tags\b|--follow-tags\b)/i, reason: "push tags (a v* tag deploys to PROD)" },
|
||||||
|
{ re: /\bgit\s+push\b[^\n]*\sv\d[\w.-]*/i, reason: "push a v* version tag (deploys to PROD)" },
|
||||||
{
|
{
|
||||||
re: /\bkubectl\b[^\n]*(--context[=\s]?\S*prod|--namespace[=\s]?\S*prod|\bctx-prod\b)/i,
|
re: /\bkubectl\b[^\n]*(--context[=\s]?\S*prod|--namespace[=\s]?\S*prod|\bctx-prod\b)/i,
|
||||||
reason: "kubectl against a production context/namespace",
|
reason: "kubectl against a production context/namespace",
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ GITLAB_TOKEN=... ./scripts/create-mr.sh "Fix PROJ-123: NPE" main "" PROJ-123
|
|||||||
|
|
||||||
Флаги окружения `create-mr.sh`: `GITLAB_TOKEN` (обязателен), `GITLAB_HOST` (override хоста),
|
Флаги окружения `create-mr.sh`: `GITLAB_TOKEN` (обязателен), `GITLAB_HOST` (override хоста),
|
||||||
`MR_PUSH=0` (не пушить ветку), `MR_DRY_RUN=1` (показать запрос без вызова API).
|
`MR_PUSH=0` (не пушить ветку), `MR_DRY_RUN=1` (показать запрос без вызова API).
|
||||||
MR из защищённой ветки (`main`/`master`/`release/*`) скрипт создавать откажется.
|
MR из защищённой/релизной ветки (`main`/`master`/`release-*`) скрипт создавать откажется.
|
||||||
|
|
||||||
## Соглашения
|
## Соглашения
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ JIRA_KEY="${4:-}"
|
|||||||
|
|
||||||
# --- Refuse to open an MR *from* a protected branch (safety). ----------------
|
# --- Refuse to open an MR *from* a protected branch (safety). ----------------
|
||||||
case "$SOURCE" in
|
case "$SOURCE" in
|
||||||
main | master | release/*)
|
main | master | release-* | release/*)
|
||||||
echo "Refusing: source branch '$SOURCE' looks protected. Create a feature branch first." >&2
|
echo "Refusing: source branch '$SOURCE' looks protected/release. Create a feature branch first." >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Reference in New Issue
Block a user