@mokoenterprises/mokossh-mcp 3.8.1 → 3.9.0

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.
@@ -1,11 +1,11 @@
1
- # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
1
+ # Copyright (C) 2026 Moko Enterprises <hello@mokoenterprises.us>
2
2
  #
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
  #
5
5
  # FILE INFORMATION
6
6
  # DEFGROUP: MokoGIT.Workflow
7
7
  # INGROUP: MokoCLI.Maintenance
8
- # REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
8
+ # REPO: https://git.mokoenterprises.us/MokoEnterprises/Template-Generic
9
9
  # PATH: /.mokogit/workflows/cleanup.yml
10
10
  # VERSION: 01.01.00
11
11
  # CHANGE (01.01.00): fail-open branch/run cleanup (#430) — the run token may lack REST read on some repos, returning an error OBJECT; `jq '.[]'` on it exit-5'd the job under pipefail (fleet-wide red). Guard type=="array" / `(.workflow_runs // [])` and skip gracefully; cleanup is best-effort housekeeping and must never red the run.
@@ -23,7 +23,7 @@ permissions:
23
23
  actions: write
24
24
 
25
25
  env:
26
- MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
26
+ MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoenterprises.us' }}
27
27
 
28
28
  jobs:
29
29
  cleanup:
@@ -1,14 +1,15 @@
1
- # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
1
+ # Copyright (C) 2026 Moko Enterprises <hello@mokoenterprises.us>
2
2
  #
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
  #
5
5
  # FILE INFORMATION
6
6
  # DEFGROUP: MokoGIT.Workflow
7
7
  # INGROUP: MokoCLI.Validation
8
- # REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
8
+ # REPO: https://git.mokoenterprises.us/MokoEnterprises/Template-Generic
9
9
  # PATH: /.mokogit/workflows/makefile-lint.yml
10
- # VERSION: 01.03.00
11
- # BRIEF: Makefile sanity lint -- identity fields + release contract (SRC_DIR, PROJECT_VERSION format, BUILD_DIR, required targets, parse). Release-contract checks are WARN by default; set vars.MAKEFILE_LINT_ENFORCE=enforce to hard-fail (JOOMLA_I18N_ENFORCE-style, per-repo opt-in). Also runs a Scaffold Placeholder Guard job that HARD-FAILS when leftover de-template placeholders ({{UPPER_SNAKE}} moustaches, Template-<Word> repo refs, and fixed literals like example_resources/CHANGEME/myproject) survive in the tracked tree; skipped on Template-* source repos and excludes .mokogit/** + CHANGELOG*.
10
+ # VERSION: 01.05.01
11
+ # CHANGE (01.05.00): Hardened the Scaffold Placeholder Guard against two false-positive classes. (1) Dropped MokonyxExample from LITERAL_ALT -- it is a documented @see example-class reference (e.g. MokonyxExampleInstallerScript) cited fleet-wide, not an un-de-templated scaffold leftover, so it false-positived legit PRs (mirrors the #524 com_example removal). (2) Excluded TRIPLE-brace from MOUSTACHE_RE -- a real placeholder is always exactly double-brace {{X}}, whereas {{{X}}} is Python f-string brace-escaping (e.g. {{{SODIPODI_NS}}} in inkscape-extensions), never a de-template leftover; the regex now uses PCRE (?<!\{)/(?!\}) lookarounds and scan() greps with -P instead of -E.
12
+ # BRIEF: NEW (01.05.01): the Scaffold Placeholder Guard now also EXCLUDES Gitea-fork test-config fixtures `tests/*.ini.tmpl` (and `tests/**/*.ini.tmpl`). Their `{{TEST_*}}`/`{{GITEA_TEST_*}}` moustache tokens are legitimate test-harness templating rendered by Gitea's own test runner, NOT de-template leftovers; they were hard-failing the guard on every MokoGIT (Gitea fork) PR (#2059). PREVIOUS: Makefile sanity lint -- identity fields + release contract (SRC_DIR, PROJECT_VERSION format, BUILD_DIR, required targets, parse). Release-contract checks are WARN by default; set vars.MAKEFILE_LINT_ENFORCE=enforce to hard-fail (JOOMLA_I18N_ENFORCE-style, per-repo opt-in). Also runs a Scaffold Placeholder Guard job that HARD-FAILS when leftover de-template placeholders (exactly-double-brace {{UPPER_SNAKE}} moustaches and fixed literals like example_resources/CHANGEME/myproject) survive in the tracked tree; skipped on Template-* source repos and excludes .mokogit/** + CHANGELOG*. The moustache scan uses PCRE lookarounds so TRIPLE-brace {{{X}}} (Python f-string brace-escaping) is NOT flagged. The bare Template-<Word> content scan, the com_example literal, and the MokonyxExample literal were removed (#524 / 01.05.00) as they false-positived on legitimate standards-repo citations and documented example hints.
12
13
  #
13
14
  # +========================================================================+
14
15
  # | MAKEFILE IDENTITY LINT |
@@ -300,10 +301,18 @@ jobs:
300
301
 
301
302
  # Literal scaffold strings that must never survive de-templating,
302
303
  # as a single pre-built alternation (so this definition line is not
303
- # itself a multi-token target the scanner would trip over). The
304
- # Template-* names here are also covered by TEMPLATE_REPO_RE below;
305
- # they are listed explicitly so the failure message is unambiguous.
306
- LITERAL_ALT='example_resources|CHANGEME|myproject|myorg|your-project|com_example|MokonyxExample'
304
+ # itself a multi-token target the scanner would trip over).
305
+ #
306
+ # Deliberately NOT included (issue #524):
307
+ # - com_example : a legitimate documentation/example token used in
308
+ # real field hints (e.g. hint="/media/com_example/*.php"), the
309
+ # matching _DESC language strings, and source/build/i18n-allow.txt.
310
+ # It is an illustrative glob, not an un-de-templated scaffold token.
311
+ # - MokonyxExample : a documented @see example-class reference (e.g.
312
+ # MokonyxExampleInstallerScript) cited fleet-wide in installer
313
+ # comments and docs. Like com_example above it is an illustrative
314
+ # reference, not a de-template leftover, so it is likewise excluded.
315
+ LITERAL_ALT='example_resources|CHANGEME|myproject|myorg|your-project'
307
316
 
308
317
  # Regexes applied per tracked file. Kept as distinct patterns so the
309
318
  # failure message can name which class of placeholder was hit.
@@ -311,9 +320,24 @@ jobs:
311
320
  # {{DISPLAY_NAME}}, {{ENV_PREFIX}}, and the general
312
321
  # {{UPPER_SNAKE}} shape. Requires [A-Z0-9_] (at least one [A-Z]),
313
322
  # so lowercase app tokens like {{tempFile}} do NOT match.
314
- # 2) Template-<Word> repo-name references in docs/content.
315
- MOUSTACHE_RE='\{\{[A-Z0-9_]*[A-Z][A-Z0-9_]*\}\}'
316
- TEMPLATE_REPO_RE='Template-[A-Z][A-Za-z0-9]+'
323
+ #
324
+ # The moustache shape plus the explicit literal set are the reliable
325
+ # de-template signals. A bare Template-<Word> word-match was REMOVED
326
+ # (issue #524): it false-positived on every legitimate citation of the
327
+ # standards repos (Template-Joomla #377 in installer comments, README
328
+ # extension tables, @see wiki links, uninstall SQL banners), which are
329
+ # correct references, not leftover scaffolding. A genuinely
330
+ # un-de-templated repo still trips the moustache/literal rules.
331
+ #
332
+ # Triple-brace EXCLUSION (PCRE lookarounds): a real scaffold
333
+ # placeholder is always EXACTLY double-brace -- {{UPPER_SNAKE}}. A
334
+ # TRIPLE-brace {{{X}}} is Python f-string brace-escaping (e.g.
335
+ # {{{SODIPODI_NS}}} in inkscape-extensions, where {{ / }} emit literal
336
+ # braces around an interpolated value), never a de-template leftover.
337
+ # The (?<!\{) / (?!\}) lookarounds reject a {{...}} that is flanked by
338
+ # a third brace, so f-string escapes no longer false-positive. This
339
+ # requires PCRE, so scan() greps with -P (see below).
340
+ MOUSTACHE_RE='(?<!\{)\{\{[A-Z0-9_]*[A-Z][A-Z0-9_]*\}\}(?!\})'
317
341
 
318
342
  # Files to exclude from the scan:
319
343
  # - .mokogit/** : carries this workflow (its own token list)
@@ -321,10 +345,15 @@ jobs:
321
345
  # - CHANGELOG* : legitimately records historical names.
322
346
  # - the moustache/literal patterns' own home is .mokogit, already out.
323
347
  # git ls-files honours .gitignore and only lists TRACKED files.
348
+ # - tests/*.ini.tmpl : Gitea-fork test-config fixtures whose
349
+ # {{TEST_*}}/{{GITEA_TEST_*}} moustaches are legitimate test-harness
350
+ # templating (rendered by Gitea's test runner), not scaffold leftovers (#2059).
324
351
  mapfile -t FILES < <(git ls-files \
325
352
  ':(exclude).mokogit/**' \
326
353
  ':(exclude)CHANGELOG*' \
327
- ':(exclude)**/CHANGELOG*')
354
+ ':(exclude)**/CHANGELOG*' \
355
+ ':(exclude)tests/*.ini.tmpl' \
356
+ ':(exclude)tests/**/*.ini.tmpl')
328
357
 
329
358
  HITS=0
330
359
 
@@ -332,19 +361,21 @@ jobs:
332
361
  local re="$1" label="$2" f
333
362
  for f in "${FILES[@]}"; do
334
363
  [ -f "$f" ] || continue
335
- # grep -nE: line number + extended regex. Binary files skipped.
336
- grep -nIE "$re" "$f" 2>/dev/null | while IFS= read -r line; do
364
+ # grep -nP: line number + PCRE. PCRE is required for the moustache
365
+ # pattern's (?<!\{)/(?!\}) lookarounds (triple-brace f-string
366
+ # exclusion). GNU grep on ubuntu-latest supports -P. The LITERAL_ALT
367
+ # plain a|b|c alternation works identically under -P. Binary skipped.
368
+ grep -nIP "$re" "$f" 2>/dev/null | while IFS= read -r line; do
337
369
  echo "::error file=${f}::Leftover scaffold placeholder (${label}): ${f}:${line}"
338
370
  done
339
- if grep -qIE "$re" "$f" 2>/dev/null; then
340
- grep -nIE "$re" "$f" 2>/dev/null | sed "s|^|- [FAIL] ${f}:|" >> "$GITHUB_STEP_SUMMARY"
371
+ if grep -qIP "$re" "$f" 2>/dev/null; then
372
+ grep -nIP "$re" "$f" 2>/dev/null | sed "s|^|- [FAIL] ${f}:|" >> "$GITHUB_STEP_SUMMARY"
341
373
  HITS=1
342
374
  fi
343
375
  done
344
376
  }
345
377
 
346
378
  scan "$MOUSTACHE_RE" "UPPER_SNAKE moustache placeholder"
347
- scan "$TEMPLATE_REPO_RE" "Template-<Word> repo reference"
348
379
  scan "$LITERAL_ALT" "literal scaffold token"
349
380
 
350
381
  if [ "$HITS" -ne 0 ]; then
@@ -1,5 +1,5 @@
1
1
  # MCP Server Build & Validation
2
- # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
2
+ # Copyright (C) 2026 Moko Enterprises <hello@mokoenterprises.us>
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
  #
5
5
  # Builds the MCP server via the centralized MokoCLI build agent
@@ -32,7 +32,7 @@ permissions:
32
32
  issues: write # folded-in Wiki Reminder posts a sticky PR comment
33
33
 
34
34
  env:
35
- MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
35
+ MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoenterprises.us' }}
36
36
  GIT_ORG: ${{ vars.MOKOGIT_ORG || github.repository_owner }}
37
37
  GIT_REPO: ${{ vars.MOKOGIT_REPO || github.event.repository.name }}
38
38
 
@@ -97,7 +97,7 @@ jobs:
97
97
  - name: Setup MokoCLI build agent (moko on PATH)
98
98
  env:
99
99
  MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
100
- MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
100
+ MOKO_CLONE_HOST: git.mokoenterprises.us/MokoEnterprises
101
101
  run: |
102
102
  # Reach mokocli deterministically and expose `moko` on PATH (mokocli's cli/ dir)
103
103
  # so `moko build|test|lint` resolve. Prefer a pre-installed /opt/mokocli ONLY
@@ -120,8 +120,8 @@ jobs:
120
120
  sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
121
121
  fi
122
122
  rm -rf /tmp/mokocli
123
- REG='{"type":"composer","url":"https://git.mokoconsulting.tech/api/packages/MokoConsulting/composer"}'
124
- if composer create-project --no-dev --no-interaction --no-progress --quiet --repository="${REG}" mokoconsulting/mokocli /tmp/mokocli >/dev/null 2>&1 && { [ -x /tmp/mokocli/cli/moko ] || [ -f /tmp/mokocli/cli/moko ]; }; then
123
+ REG='{"type":"composer","url":"https://git.mokoenterprises.us/api/packages/MokoEnterprises/composer"}'
124
+ if composer create-project --no-dev --no-interaction --no-progress --quiet --repository="${REG}" mokoenterprises/mokocli /tmp/mokocli >/dev/null 2>&1 && { [ -x /tmp/mokocli/cli/moko ] || [ -f /tmp/mokocli/cli/moko ]; }; then
125
125
  echo "Bootstrapped mokocli from the Composer registry (tokenless)."
126
126
  else
127
127
  echo "Registry bootstrap unavailable; falling back to authenticated git clone."
@@ -355,7 +355,7 @@ jobs:
355
355
  BASE_SHA: ${{ github.event.pull_request.base.sha }}
356
356
  HEAD_SHA: ${{ github.event.pull_request.head.sha }}
357
357
  PR_CREATED_AT: ${{ github.event.pull_request.created_at }}
358
- SERVER: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
358
+ SERVER: ${{ vars.MOKOGIT_URL || 'https://git.mokoenterprises.us' }}
359
359
  REPO: ${{ github.repository }}
360
360
  TOKEN: ${{ github.token }}
361
361
  DOCS_WIKI_WINDOW: ${{ vars.DOCS_WIKI_WINDOW || 'pr' }}
@@ -467,7 +467,7 @@ jobs:
467
467
  - name: Remind to update the wiki
468
468
  env:
469
469
  TOKEN: ${{ github.token }}
470
- SERVER: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
470
+ SERVER: ${{ vars.MOKOGIT_URL || 'https://git.mokoenterprises.us' }}
471
471
  REPO: ${{ github.repository }}
472
472
  PR: ${{ github.event.pull_request.number }}
473
473
  run: |
@@ -475,7 +475,7 @@ jobs:
475
475
  {
476
476
  echo "## Wiki Update Reminder"
477
477
  echo ""
478
- echo "Docs are **wiki-first** at MokoConsulting. If this change affects behavior, usage, configuration, or standards, update the repo wiki:"
478
+ echo "Docs are **wiki-first** at MokoEnterprises. If this change affects behavior, usage, configuration, or standards, update the repo wiki:"
479
479
  echo ""
480
480
  echo "- ${SERVER}/${REPO}/wiki"
481
481
  echo ""
@@ -1,5 +1,5 @@
1
1
  # MCP SDK Version Check
2
- # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
2
+ # Copyright (C) 2026 Moko Enterprises <hello@mokoenterprises.us>
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
  #
5
5
  # Weekly check for MCP SDK updates. Creates an issue when a new version
@@ -1,5 +1,5 @@
1
1
  # MCP Tool Inventory
2
- # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
2
+ # Copyright (C) 2026 Moko Enterprises <hello@mokoenterprises.us>
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
  #
5
5
  # Generates a tool inventory report on each push to main.
@@ -18,7 +18,7 @@ permissions:
18
18
  contents: read
19
19
 
20
20
  env:
21
- MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoconsulting.tech' }}
21
+ MOKOGIT_URL: ${{ vars.MOKOGIT_URL || 'https://git.mokoenterprises.us' }}
22
22
  GIT_ORG: ${{ vars.MOKOGIT_ORG || github.repository_owner }}
23
23
  GIT_REPO: ${{ vars.MOKOGIT_REPO || github.event.repository.name }}
24
24
 
@@ -1,92 +1,92 @@
1
- # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
2
- # SPDX-License-Identifier: GPL-3.0-or-later
3
- #
4
- # Enforces branch merge policy:
5
- # feature/* → dev only
6
- # fix/* → dev only
7
- # hotfix/* → dev or main (emergency)
8
- # dev → main only
9
- # alpha/* → dev only
10
- # beta/* → dev only
11
- # rc/* → main only
12
-
13
- name: Branch Policy Check
14
-
15
- on:
16
- pull_request:
17
- types: [opened, synchronize, reopened, edited]
18
-
19
- jobs:
20
- check-target:
21
- name: Verify merge target
22
- runs-on: ubuntu-latest
23
- steps:
24
- - name: Check branch policy
25
- env:
26
- DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
27
- run: |
28
- HEAD="${{ github.head_ref }}"
29
- BASE="${{ github.base_ref }}"
30
-
31
- echo "PR: ${HEAD} → ${BASE}"
32
-
33
- ALLOWED=true
34
- REASON=""
35
-
36
- case "$HEAD" in
37
- feature/*|feat/*)
38
- if [ "$BASE" != "dev" ]; then
39
- ALLOWED=false
40
- REASON="Feature branches must target 'dev', not '${BASE}'"
41
- fi
42
- ;;
43
- fix/*|bugfix/*)
44
- if [ "$BASE" != "dev" ]; then
45
- ALLOWED=false
46
- REASON="Fix branches must target 'dev', not '${BASE}'"
47
- fi
48
- ;;
49
- hotfix/*)
50
- if [ "$BASE" != "dev" ] && [ "$BASE" != "$DEFAULT_BRANCH" ]; then
51
- ALLOWED=false
52
- REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
53
- fi
54
- ;;
55
- alpha/*|beta/*)
56
- if [ "$BASE" != "dev" ]; then
57
- ALLOWED=false
58
- REASON="Pre-release branches must target 'dev', not '${BASE}'"
59
- fi
60
- ;;
61
- rc/*)
62
- if [ "$BASE" != "$DEFAULT_BRANCH" ]; then
63
- ALLOWED=false
64
- REASON="Release candidate branches must target 'main', not '${BASE}'"
65
- fi
66
- ;;
67
- dev)
68
- if [ "$BASE" != "$DEFAULT_BRANCH" ]; then
69
- ALLOWED=false
70
- REASON="Dev branch can only merge into 'main', not '${BASE}'"
71
- fi
72
- ;;
73
- esac
74
-
75
- if [ "$ALLOWED" = false ]; then
76
- echo "::error::${REASON}"
77
- echo ""
78
- echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY
79
- echo "" >> $GITHUB_STEP_SUMMARY
80
- echo "${REASON}" >> $GITHUB_STEP_SUMMARY
81
- echo "" >> $GITHUB_STEP_SUMMARY
82
- echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY
83
- echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
84
- echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
85
- echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY
86
- echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY
87
- echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY
88
- exit 1
89
- fi
90
-
91
- echo "Branch policy: OK (${HEAD} → ${BASE})"
92
- echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY
1
+ # Copyright (C) 2026 Moko Enterprises <hello@mokoenterprises.us>
2
+ # SPDX-License-Identifier: GPL-3.0-or-later
3
+ #
4
+ # Enforces branch merge policy:
5
+ # feature/* → dev only
6
+ # fix/* → dev only
7
+ # hotfix/* → dev or main (emergency)
8
+ # dev → main only
9
+ # alpha/* → dev only
10
+ # beta/* → dev only
11
+ # rc/* → main only
12
+
13
+ name: Branch Policy Check
14
+
15
+ on:
16
+ pull_request:
17
+ types: [opened, synchronize, reopened, edited]
18
+
19
+ jobs:
20
+ check-target:
21
+ name: Verify merge target
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - name: Check branch policy
25
+ env:
26
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
27
+ run: |
28
+ HEAD="${{ github.head_ref }}"
29
+ BASE="${{ github.base_ref }}"
30
+
31
+ echo "PR: ${HEAD} → ${BASE}"
32
+
33
+ ALLOWED=true
34
+ REASON=""
35
+
36
+ case "$HEAD" in
37
+ feature/*|feat/*)
38
+ if [ "$BASE" != "dev" ]; then
39
+ ALLOWED=false
40
+ REASON="Feature branches must target 'dev', not '${BASE}'"
41
+ fi
42
+ ;;
43
+ fix/*|bugfix/*)
44
+ if [ "$BASE" != "dev" ]; then
45
+ ALLOWED=false
46
+ REASON="Fix branches must target 'dev', not '${BASE}'"
47
+ fi
48
+ ;;
49
+ hotfix/*)
50
+ if [ "$BASE" != "dev" ] && [ "$BASE" != "$DEFAULT_BRANCH" ]; then
51
+ ALLOWED=false
52
+ REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
53
+ fi
54
+ ;;
55
+ alpha/*|beta/*)
56
+ if [ "$BASE" != "dev" ]; then
57
+ ALLOWED=false
58
+ REASON="Pre-release branches must target 'dev', not '${BASE}'"
59
+ fi
60
+ ;;
61
+ rc/*)
62
+ if [ "$BASE" != "$DEFAULT_BRANCH" ]; then
63
+ ALLOWED=false
64
+ REASON="Release candidate branches must target 'main', not '${BASE}'"
65
+ fi
66
+ ;;
67
+ dev)
68
+ if [ "$BASE" != "$DEFAULT_BRANCH" ]; then
69
+ ALLOWED=false
70
+ REASON="Dev branch can only merge into 'main', not '${BASE}'"
71
+ fi
72
+ ;;
73
+ esac
74
+
75
+ if [ "$ALLOWED" = false ]; then
76
+ echo "::error::${REASON}"
77
+ echo ""
78
+ echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY
79
+ echo "" >> $GITHUB_STEP_SUMMARY
80
+ echo "${REASON}" >> $GITHUB_STEP_SUMMARY
81
+ echo "" >> $GITHUB_STEP_SUMMARY
82
+ echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY
83
+ echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
84
+ echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
85
+ echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY
86
+ echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY
87
+ echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY
88
+ exit 1
89
+ fi
90
+
91
+ echo "Branch policy: OK (${HEAD} → ${BASE})"
92
+ echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY