engineering-handbook/github-standards.md
Adam Moussa efec84a07a
docs(deps): replace Dependabot version-update policy with Renovate (#51)
* docs(deps): replace Dependabot version-update policy with Renovate

* docs(deps): reconcile Renovate policy with exact-pin and ruleset names
2026-10-05 18:09:43 +00:00

9.9 KiB

GitHub Standards

Repository Defaults

  • Default branch: main
  • Every repo gets a one-line description
  • Every repo gets standard topics and a README badge block (see below)
  • Default to private visibility for org repos
  • Dependabot alerts enabled on all active repos. Version updates and security-fix PRs come from Renovate, not Dependabot.
  • Org-level defaults auto-enable alerts on new repos
  • Every repo with dependencies gets a root renovate.json that extends the org preset (see Dependency Updates). Do not add .github/dependabot.yml.
  • Merge settings: enable auto-merge and auto-delete head branch on merge (allow_auto_merge + delete_branch_on_merge). These have no org-level default — set them per-repo at provisioning.

Security & Merge Baseline

Every active repo runs the same baseline. The security half is meant to be carried by the org Code Security Configuration "Sea Haven Standard" (enforced, default_for_new_repos: all); attach it to the repo at creation so new repos inherit it instead of drifting. The merge half (allow_auto_merge, delete_branch_on_merge) is not covered by any org config and must be set per-repo.

Setting Baseline Mechanism
allow_auto_merge enabled per-repo (gh api repos/<org>/<repo> -X PATCH -F allow_auto_merge=true)
delete_branch_on_merge enabled per-repo (-F delete_branch_on_merge=true)
code_security (advanced security) enabled Sea Haven Standard config
Secret scanning + push protection enabled Sea Haven Standard config
Secret scanning non-provider patterns + validity checks enabled per-repo until added to the config
Dependabot alerts enabled org auto-enable default + config
Dependabot security-update PRs disabled once the repo is Interactive in Renovate per-repo; Renovate opens the CVE fix PR instead
CodeQL default setup configured per-repo (PATCH .../code-scanning/default-setup state=configured) until added to the config

Exceptions:

  • Docs-only repos (e.g. engineering-handbook) skip CodeQL — there is no compiled code to scan; code_security may stay off. Secret scanning still applies.
  • shoc-backend / shoc-frontend-new are excluded from org compliance tooling (see the .github org-config notes); leave their settings to the SHOC team.

To audit drift: gh api repos/<org>/<repo> --jq '{allow_auto_merge, delete_branch_on_merge, security_and_analysis}' and gh api repos/<org>/<repo>/code-scanning/default-setup --jq .state.

Dependency Updates

Sea Haven uses the Mend Renovate GitHub App for dependency updates. Dependabot version updates are not used; do not add .github/dependabot.yml. Dependabot alerts stay on, and Dependabot security-update PRs are turned off once a repo is Interactive in Renovate so CVE fixes are not opened twice.

The org-wide policy lives in the Sea-Haven-Industries/renovate-config repo (org-inherited-config.json), which Mend applies to every repo automatically. Each repo also carries a root renovate.json so the preset chain is visible in the repo:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["local>Sea-Haven-Industries/.github"]
}

Renovate detects package files on its own (package.json, requirements.txt, .csproj, .tf, workflow files). No per-ecosystem configuration is needed in the repo. Flip a repo from Silent to Interactive in the Mend Developer Portal when it should start receiving PRs.

Pinning Principle

Pins are for reproducibility, not for freezing time. The pinned version is kept current by Renovate PRs gated by CI and dependency review, never by a version number written in documentation.

  • npm, pip, and Terraform providers keep whatever range style the repo already uses (rangeStrategy: bump): a caret range is bumped to a new caret range and an exact pin is bumped to a new exact pin. The lockfile is the pin for ranged dependencies. Dependencies under an explicit exact-pin policy, such as aws-cdk-lib (see aws-infrastructure.md), stay exact. GitHub Actions are pinned to a full commit SHA with a # vX.Y.Z comment.
  • Runtime and language versions (node-version, python-version, Terraform required_version, .terraform-version) are not bumped by Renovate.
  • Never add a blanket ignore for a dependency. If a specific release is broken, add a packageRules entry in the repo's renovate.json that excludes that version only, explain why in the rule's description field (renovate.json is strict JSON and cannot carry comments), and remove it once a fixed release ships.
  • Never dismiss a vulnerability alert as "waiting for upstream" without a linked follow-up that advances the pin when the fix ships.
  • If a bump PR fails CI, the gate worked. Leave the bad release unmerged and take the next one.

Merging Renovate PRs

  • Minor, patch, pin, and digest updates are grouped per ecosystem and automerge once every check on the PR passes. Renovate merges the PR itself with squash and is a bypass actor on the main branch review ruleset and the per-repo main merge queue rulesets, so no human approval is needed. Required status checks still apply.
  • Major version bumps and security PRs are not automerged. Review the changelog for breaking changes, then merge by hand.
  • Renovate waits three days after a release before proposing it (minimumReleaseAge). Security PRs skip the wait.
  • Renovate PRs do not need a Jira key.

Branch Protection

  • Require a PR for merges to main (no direct push)
  • No force push to main
  • No branch deletion for main

Agents and Automation

Agents and automation (CI bots, Cursor agents, scripts) do not push directly to main unless Adam has explicitly directed it for a specific action. The default path for any automated change is a branch and a PR, same as human-authored work.

GitHub Environments

HCP app repos use Environments as the deploy gate. See cicd.md.

Environment Reviewers Deployment branch policy Variables
dev none main DEPLOY_ROLE_ARN
prod required main and v* DEPLOY_ROLE_ARN

DEPLOY_ROLE_ARN is an Environment variable, not a repo secret. Remaining SAM/CDK repos may still use AWS_DEPLOY_ROLE_ARN as a repo secret until they migrate.

Converted HCP CD callers pin OIDC with both claims: job_workflow_ref on the org reusable (cd-hcp-fargate.yaml / cd-hcp-spa.yaml) and workflow_ref on the thin repo caller at refs/heads/main and refs/tags/v*. sub stays repo:.../<app>:environment:<env>. Details are in cicd.md.

README Badges

Every repo's README carries a small badge block immediately under the H1. Use static badges only — dynamic badges (for example shields.io last-commit or open-issues) query the public GitHub API and render broken on private repos.

  • CI status: the GitHub-native workflow badge (.../actions/workflows/<ci-file>/badge.svg), and only when a CI workflow exists. On private repos it renders only for logged-in org members — that is accepted.
  • Stack: two to four static shields.io badges for the language and IaC/runtime (Python / TypeScript / .NET, HCP Terraform / AWS SAM / CDK), plus a Slack badge when the repo integrates Slack.
  • Keep badges static so they never go stale; version-pinned badges drift.

Repository Topics

Every repo gets a set of lowercase, hyphenated topics so the org is filterable by stack and purpose. Draw from a consistent vocabulary:

  • Cloud / IaC: aws, terraform, hcp, sam, cdk, lambda, ec2, s3, cloudfront
  • Language: python, typescript, javascript, dotnet, react, nodejs
  • Integration / domain: slack, bedrock, ai, security, internal-tool, documentation

Set them with gh repo edit <repo> --add-topic a,b,c. Adding topics is part of new-repo provisioning, not a follow-up.

Required CI Status Check

Two org rulesets carry the required status check. A repo is on exactly one of them. Never both.

Ruleset Required check Who
main branch protection ci / ci Unconverted remaining-lane repos
CI complete ci-complete Converted HCP callers

A third org ruleset, main branch review, carries the pull request rule (one approving review, squash only) for every repo except shoc-backend, shoc-frontend-new, open-swe, and .github-private. Each repo also has its own main merge queue ruleset.

CI complete starts with no repos. Flip include/unexclude in the same window as the workflow merge that lands name: ci-complete. Do not put portion names (frontend / static, unit (1), browser-smoke) in a ruleset.

If the check name in the ruleset does not match what CI actually emits, merges will be blocked by a phantom required check. Verify after any change to CI job names.

Mergify YAML is not used. Converted CI keeps a merge_group trigger so native GitHub merge queues still run. Do not treat a missing Mergify config as a gap. Do not remove or retarget native GitHub merge-queue rulesets when flipping CI membership.

The formatter GitHub App is not on the main-branch ruleset bypass list. The Renovate GitHub App is a bypass actor on main branch review and on each repo's main merge queue ruleset so it can merge its own non-major PRs; it is not a bypass actor on the required-status-check rulesets.

Repo Hygiene

  • Delete feature branches after merge
  • Archive repos that are no longer actively developed (close issues first)
  • Don't delete repos unless truly disposable
  • Scrub all company-specific info from git history before making any repo public

Public Repos

Before making a repo public, verify the entire git history contains no:

  • Phone numbers or customer data
  • API subdomains or internal URLs
  • Webhook endpoints
  • Employee names or internal identifiers

If sensitive data was committed at any point, start fresh with a clean git init rather than rewriting history.