From 6a2a8c14ab21db5710fe53d6800ba0a7cff06e32 Mon Sep 17 00:00:00 2001 From: heznpc Date: Wed, 9 Sep 2026 16:43:05 +0900 Subject: [PATCH 1/2] chore: adopt centralized Starter Series fleet policy --- .github/actions/validate/action.yml | 17 +++++ .github/workflows/ci.yml | 102 +++++----------------------- .github/workflows/codeql.yml | 40 +++-------- .github/workflows/maintenance.yml | 90 +----------------------- AGENTS.md | 8 +++ 5 files changed, 53 insertions(+), 204 deletions(-) create mode 100644 .github/actions/validate/action.yml diff --git a/.github/actions/validate/action.yml b/.github/actions/validate/action.yml new file mode 100644 index 0000000..47c7b5e --- /dev/null +++ b/.github/actions/validate/action.yml @@ -0,0 +1,17 @@ +name: Validate python-mcp-server-starter +description: Deliverable-specific checks; runtime and security policy live in starter-series/.github. +runs: + using: composite + steps: + - name: Lint + run: ruff check . + shell: bash + - name: Format check + run: ruff format --check . + shell: bash + - name: Type check + run: mypy src/ + shell: bash + - name: Test (with coverage) + run: pytest -v --cov=my_mcp_server --cov-report=term-missing --cov-fail-under=70 + shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fad8ef2..e759812 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,94 +1,24 @@ name: CI - -on: +'on': push: - branches: [main] + branches: + - main pull_request: - branches: [main] - workflow_call: - + branches: + - main + workflow_call: {} + workflow_dispatch: {} permissions: contents: read - jobs: - security: + checks: + uses: starter-series/.github/.github/workflows/reusable-python-ci.yml@main + ci: + if: ${{ always() }} + needs: + - checks runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Scan for secrets - env: - # Bump together; checksum from - # https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_checksums.txt - GITLEAKS_VERSION: 8.30.1 - GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb - run: | - set -euo pipefail - curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o /tmp/gitleaks.tgz - echo "${GITLEAKS_SHA256} /tmp/gitleaks.tgz" | sha256sum -c - - tar xz -C /tmp -f /tmp/gitleaks.tgz - /tmp/gitleaks detect --source . --verbose --redact - - - name: Check for large files - run: | - LARGE=$(find . -not -path './.git/*' -not -path './.venv/*' -type f -size +5M) - if [ -n "$LARGE" ]; then - echo "::error::Large files detected (>5 MB):" - echo "$LARGE" - exit 1 - fi - - licenses: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - - uses: actions/setup-python@v6 - with: - python-version: "3.13" - cache: pip - cache-dependency-path: pyproject.toml - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -e ".[dev]" - - - name: Check licenses - run: pip-licenses --fail-on="GPL-2.0;GPL-3.0;AGPL-3.0" - - test: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.11", "3.12", "3.13"] - steps: - - uses: actions/checkout@v6 - - - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python-version }} - cache: pip - cache-dependency-path: pyproject.toml - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install -e ".[dev]" - - - name: Dependency audit (pip-audit) - run: pip-audit . --strict - - - name: Lint - run: ruff check . - - - name: Format check - run: ruff format --check . - - - name: Type check - run: mypy src/ - - - name: Test (with coverage) - run: pytest -v --cov=my_mcp_server --cov-report=term-missing --cov-fail-under=70 + - uses: starter-series/.github/.github/actions/require-checks@main + with: + results: ${{ toJSON(needs) }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 44fea7c..8fabe52 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,39 +1,17 @@ name: CodeQL - -on: +'on': push: - branches: [main] + branches: + - main pull_request: - branches: [main] - schedule: - - cron: '0 6 * * 1' # Every Monday 06:00 UTC - + branches: + - main + workflow_dispatch: {} permissions: contents: read security-events: write - jobs: analyze: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - # `actions` scans .github/workflows/ for workflow-level issues - # (script injection, missing permissions, etc.). - language: [python, actions] - steps: - - uses: actions/checkout@v6 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: ${{ matrix.language }} - - - name: Autobuild - if: matrix.language == 'python' - uses: github/codeql-action/autobuild@v4 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:${{ matrix.language }}" + uses: starter-series/.github/.github/workflows/reusable-codeql.yml@main + with: + language: python diff --git a/.github/workflows/maintenance.yml b/.github/workflows/maintenance.yml index e9a5ca9..616e6f3 100644 --- a/.github/workflows/maintenance.yml +++ b/.github/workflows/maintenance.yml @@ -1,92 +1,8 @@ -name: Maintenance - -on: - schedule: - - cron: '0 0 * * 0' - workflow_dispatch: - +name: Maintenance (manual) +'on': + workflow_dispatch: {} permissions: contents: read - issues: write - jobs: ci: uses: ./.github/workflows/ci.yml - - open-issue-on-failure: - needs: ci - if: failure() - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - const existing = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - labels: 'maintenance', - }); - if (existing.data.length > 0) { - console.log('Open maintenance issue already exists, skipping.'); - return; - } - const run = await github.rest.actions.getWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.runId, - }); - await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: 'Maintenance CI failed', - body: `The scheduled maintenance CI check failed.\n\n` + - `**Run:** ${run.data.html_url}\n\n` + - `Please check for dependency vulnerabilities, license issues, or build failures.\n\n` + - `---\n_Opened automatically by the Maintenance workflow._`, - labels: ['maintenance'], - }); - - close-issue-on-success: - needs: ci - if: success() - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - // Close any open maintenance issues — the most recent CI run - // proves the underlying problem is resolved. Without this job - // the issues opened by `open-issue-on-failure` linger forever - // and the repo looks broken to outside visitors even after the - // fix lands. - const open = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - labels: 'maintenance', - }); - if (open.data.length === 0) { - console.log('No open maintenance issues to close.'); - return; - } - const run = await github.rest.actions.getWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.runId, - }); - for (const issue of open.data) { - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body: `Maintenance CI is green again — closing automatically.\n\n**Run:** ${run.data.html_url}`, - }); - await github.rest.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - state: 'closed', - }); - console.log(`Closed issue #${issue.number}`); - } diff --git a/AGENTS.md b/AGENTS.md index 3357ac5..1f1a9c8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -87,3 +87,11 @@ For larger servers, copy the `register(mcp)` pattern from checks without documenting the tradeoff. - Do not add required secrets for normal CI. Publishing may require platform setup, but CI should stay secret-free. + +## Fleet CI policy + +Common runtime, audit, license, secret-scan and CodeQL policy lives in +[starter-series/.github](https://github.com/starter-series/.github). +Keep deliverable checks in `.github/actions/validate/action.yml`. +Weekly health and failures are aggregated in the central Fleet maintenance workflow; +this repository retains a manual maintenance runner without issue automation. From 9aa34a58608f3ec5a550fac2926c395fff481975 Mon Sep 17 00:00:00 2001 From: heznpc Date: Wed, 9 Sep 2026 16:48:22 +0900 Subject: [PATCH 2/2] docs: satisfy existing Python format gate for code examples --- README.ko.md | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.ko.md b/README.ko.md index 7234816..e635963 100644 --- a/README.ko.md +++ b/README.ko.md @@ -97,6 +97,7 @@ def register(mcp: FastMCP) -> None: ```python from my_mcp_server.resources.your_resource import register as register_your_resource + register_your_resource(mcp) ``` diff --git a/README.md b/README.md index 03cdfe4..4d03c9e 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ Then in `server.py`: ```python from my_mcp_server.resources.your_resource import register as register_your_resource + register_your_resource(mcp) ```