Skip to content
This repository was archived by the owner on May 5, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 8 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
7 changes: 7 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,10 @@
/scripts/openclaw-npm-publish.sh @openclaw/openclaw-release-managers
/scripts/openclaw-npm-release-check.ts @openclaw/openclaw-release-managers
/scripts/release-check.ts @openclaw/openclaw-release-managers

# ProdClaw downstream governance and release surfaces.
# Keep these rules last so broader upstream workflow rules cannot override @timeleft-- or @ogamel.
/PRODCLAW.md @timeleft-- @ogamel
/PRODCLAW_UPSTREAM.json @timeleft-- @ogamel
/docs/reference/prodclaw-release-policy.md @timeleft-- @ogamel
/.github/workflows/prodclaw-*.yml @timeleft-- @ogamel
3 changes: 3 additions & 0 deletions .github/workflows/auto-response.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ permissions: {}

jobs:
auto-response:
# ProdClaw does not carry OpenClaw maintainer app secrets. Keep this
# inherited automation upstream-only unless ProdClaw deliberately replaces it.
if: github.repository == 'openclaw/openclaw' || github.repository == 'openclaw-org/openclaw'
permissions:
contents: read
issues: write
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ permissions: {}

jobs:
label:
# ProdClaw does not carry OpenClaw maintainer app secrets. Keep this
# inherited triage automation upstream-only unless ProdClaw deliberately replaces it.
if: github.repository == 'openclaw/openclaw' || github.repository == 'openclaw-org/openclaw'
permissions:
contents: read
pull-requests: write
Expand Down Expand Up @@ -441,7 +444,7 @@ jobs:
}

backfill-pr-labels:
if: github.event_name == 'workflow_dispatch'
if: github.event_name == 'workflow_dispatch' && (github.repository == 'openclaw/openclaw' || github.repository == 'openclaw-org/openclaw')
permissions:
contents: read
pull-requests: write
Expand Down Expand Up @@ -741,6 +744,7 @@ jobs:
core.info(`Processed ${processed} pull requests.`);

label-issues:
if: github.repository == 'openclaw/openclaw' || github.repository == 'openclaw-org/openclaw'
permissions:
issues: write
runs-on: ubuntu-24.04
Expand Down
117 changes: 117 additions & 0 deletions .github/workflows/prodclaw-governance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: ProdClaw Governance

on:
pull_request:
types: [opened, edited, synchronize, reopened, ready_for_review]
workflow_dispatch:

permissions:
contents: read
pull-requests: write

jobs:
semantic-pr:
name: Validate PR
if: ${{ github.event_name == 'pull_request' }}
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Check PR title
id: lint-pr-title
uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Add PR title error comment
uses: marocchino/sticky-pull-request-comment@d2ad0de260ae8b0235ce059e63f2949ba9e05943
if: always() && (steps.lint-pr-title.outputs.error_message != null)
with:
header: prodclaw-pr-title-lint-error
message: |
ProdClaw PR titles must follow Conventional Commits.

```
${{ steps.lint-pr-title.outputs.error_message }}
```

- name: Delete PR title error comment
uses: marocchino/sticky-pull-request-comment@d2ad0de260ae8b0235ce059e63f2949ba9e05943
if: ${{ steps.lint-pr-title.outputs.error_message == null }}
with:
header: prodclaw-pr-title-lint-error
delete: true

prodclaw-governance:
name: ProdClaw Governance
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false

- name: Validate ProdClaw boundary docs
shell: bash
run: |
set -euo pipefail
files=(
PRODCLAW.md
docs/reference/prodclaw-release-policy.md
AGENTS.md
CONTRIBUTING.md
PRODCLAW_UPSTREAM.json
.github/workflows/prodclaw-governance.yml
.github/workflows/prodclaw-release.yml
)

for f in "${files[@]}"; do
test -f "$f"
done

# These checks are lightweight tripwires for accidental boundary-doc deletion.
# CODEOWNERS review is still the authoritative governance control.
grep -q "\\*\\*GA\\*\\* is the current production-ready channel" PRODCLAW.md
grep -q "\\*\\*LTS\\*\\* is the conservative channel" PRODCLAW.md
grep -q "at least 10 days old" PRODCLAW.md
grep -q "ProdClaw uses SemVer tags" PRODCLAW.md

private_pattern='MachineWisdomAI/''iris|iris''-[a-z0-9-]+|azureuser''@|/Users''/|/home/''younes|OPENROUTER_''API_KEY|TELEGRAM_''BOT_TOKEN'
if grep -RInE "$private_pattern" "${files[@]}"; then
echo "ProdClaw governance files must not contain private deployment details." >&2
exit 1
fi

Comment thread
timeleft-- marked this conversation as resolved.
- name: Validate ProdClaw tag policy
shell: bash
run: |
set -euo pipefail
node --input-type=module <<'NODE'
const accepted = [
"v1.0.0",
"v1.2.3",
"v2.0.0-rc.1",
"v12.34.56-rc.10",
"v1.0.0-rc.10",
];
const rejected = [
"v2026.4.27",
"2026.4.27",
"v1.0",
"v1.0.0-beta.1",
"v0.1.0",
"v1.02.3",
"v1.2.03",
"v1.2.3-rc.01",
];
const pattern = /^v(?!\d{4}\.)[1-9]\d*\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-rc\.[1-9]\d*)?$/;
for (const tag of accepted) {
if (!pattern.test(tag)) {
throw new Error(`expected accepted ProdClaw tag: ${tag}`);
}
}
for (const tag of rejected) {
if (pattern.test(tag)) {
throw new Error(`expected rejected ProdClaw tag: ${tag}`);
}
}
NODE
Loading
Loading