Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
28 changes: 28 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "github-ops-app",
"image": "mcr.microsoft.com/devcontainers/base:bookworm",
"features": {
"ghcr.io/devcontainers/features/go:1": {
"version": "1.27"
},
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
},
"forwardPorts": [8080],
"postCreateCommand": "go mod download",
"customizations": {
"vscode": {
"extensions": [
"editorconfig.editorconfig",
"github.vscode-github-actions",
"golang.go"
],
"settings": {
"editor.formatOnSave": true,
"go.lintTool": "golangci-lint-v2",
"[markdown]": {
"editor.rulers": [80]
}
}
}
}
}
14 changes: 10 additions & 4 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
.local/
.git
.github
.devcontainer
.worktrees
.local
.env
dist/
tmp/
.git/
dist
release
tmp
coverage.out
.DS_Store
77 changes: 48 additions & 29 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,50 +1,69 @@
# debug
APP_DEBUG_ENABLED=false
# every value may instead be an ssm parameter arn, such as
# arn:aws:ssm:us-east-1:123456789012:parameter/github-ops-app/slack-token

# admin token for /server/* and /scheduled/* endpoints (optional)
# when set, requests to these endpoints require "Authorization: Bearer <token>"
# APP_ADMIN_TOKEN=your-secret-admin-token
# logging: debug, info, warn, or error (default: info)
# APP_LOG_LEVEL=info

# server (cmd/server only)
# APP_LISTEN_ADDR=:8080
# routes are served under this path, such as an api gateway stage (optional)
# APP_BASE_PATH=/prod
# external url of the service, including APP_BASE_PATH; used by the installer
# APP_PUBLIC_URL=https://github-ops.example.com

# admin token for /server/* and /scheduled/*, at least 16 characters; the
# admin endpoints are disabled when it is unset
# APP_ADMIN_TOKEN=change-me-to-a-long-random-string

# github app (required)
APP_GITHUB_ORG=acme
APP_GITHUB_APP_ID=123456
APP_GITHUB_APP_PRIVATE_KEY_PATH=./.local/private-key.pem
APP_GITHUB_INSTALLATION_ID=987654
APP_GITHUB_ORG=cruxstack
APP_GITHUB_WEBHOOK_SECRET=your-webhook-secret-here
APP_GITHUB_APP_PRIVATE_KEY_PATH=./.local/github-private-key.pem
# or the key itself, with literal newlines or \n escapes
# APP_GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
APP_GITHUB_WEBHOOK_SECRET=change-me
# looked up from the organization when unset
# APP_GITHUB_INSTALLATION_ID=987654
# api url for github enterprise server
# APP_GITHUB_BASE_URL=https://github.example.com/api/v3

# github app installer (optional): serves /setup to create the app from a
# manifest and saves its credentials; disable it once the app is created
# GITHUB_APP_INSTALLER_ENABLED=true
# STORAGE_MODE=envfile # envfile or aws-ssm
# STORAGE_DIR=./.env # env file the envfile mode writes
# AWS_SSM_PARAMETER_PREFIX=/github-ops-app/
# AWS_SSM_KMS_KEY_ID=alias/github-ops-app

# github pr compliance (optional)
# pr compliance (optional)
APP_PR_COMPLIANCE_ENABLED=true
APP_PR_MONITORED_BRANCHES=main,master
# branch names or glob patterns
APP_PR_MONITORED_BRANCHES=main,master,release/*

# okta (optional)
APP_OKTA_DOMAIN=company.okta.com
# okta group sync (optional; setting any okta value requires all of them)
APP_OKTA_DOMAIN=acme.okta.com
APP_OKTA_CLIENT_ID=0oaxxxxxxxxxxxxxxxxxxxxx
APP_OKTA_PRIVATE_KEY_PATH=./.local/okta-private-key.pem
# APP_OKTA_PRIVATE_KEY_ID=kid-from-okta
# APP_OKTA_SCOPES=okta.groups.read,okta.users.read

# okta sync rules
APP_OKTA_GITHUB_USER_FIELD=githubUsername
APP_OKTA_SYNC_RULES=[{"name":"sync-eng","enabled":true,"okta_group_pattern":"^github-eng-.*","github_team_prefix":"eng-","strip_prefix":"github-eng-","sync_members":true,"create_team_if_missing":true}]
# APP_OKTA_SYNC_SAFETY_THRESHOLD=0.5 # Prevent mass removal if more than 50% would be removed (default: 0.5)
APP_OKTA_SYNC_RULES=[{"name":"sync-eng","okta_group_pattern":"^github-eng-.*","strip_prefix":"github-eng-","github_team_prefix":"eng-","create_team_if_missing":true}]
# refuse to remove more than this share of a team's members (default: 0.5)
# APP_OKTA_SYNC_SAFETY_THRESHOLD=0.5
# APP_OKTA_ORPHANED_USER_NOTIFICATIONS=true

# security alerts monitoring (optional)
# stale security alerts (optional)
# APP_SECURITY_ALERTS_ENABLED=true
# APP_SECURITY_ALERTS_MIN_AGE_DAYS=30 # only report alerts older than N days (default: 30)
# APP_SECURITY_ALERTS_MIN_SEVERITY=high # minimum severity: critical, high, medium, low (default: high)
# APP_SECURITY_ALERTS_MIN_AGE_DAYS=30
# APP_SECURITY_ALERTS_MIN_SEVERITY=high

# slack configuration (optional)
# slack (optional; the token and channel are required together)
APP_SLACK_TOKEN=xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
APP_SLACK_CHANNEL=C01234ABCDE
# optional: per-notification-type channels (fall back to APP_SLACK_CHANNEL)
# per notification type; each falls back to APP_SLACK_CHANNEL
# APP_SLACK_CHANNEL_PR_BYPASS=C01234ABCDE
# APP_SLACK_CHANNEL_OKTA_SYNC=C01234ABCDE
# APP_SLACK_CHANNEL_ORPHANED_USERS=C01234ABCDE
# APP_SLACK_CHANNEL_SECURITY_ALERTS=C01234ABCDE
# optional: custom footer note for PR bypass notifications (supports Slack mrkdwn)
# footer for pr bypass notifications, in slack mrkdwn
# APP_SLACK_FOOTER_NOTE_PR_BYPASS=_Please review the <https://example.com/policy|security policy>._

# api gateway base path (optional, for lambda deployments with stage prefix)
# APP_BASE_PATH=v1

# server port (optional, for cmd/server only, default: 8080)
# APP_PORT=8080
11 changes: 0 additions & 11 deletions .github/.dependabot.yaml

This file was deleted.

26 changes: 26 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
github-actions:
patterns: ["*"]

- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
groups:
go-modules:
patterns: ["*"]

# base images in the Dockerfile
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
groups:
docker:
patterns: ["*"]
87 changes: 55 additions & 32 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,63 +5,86 @@ on:
branches:
- main
pull_request:
branches:
- main

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4

uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: '1.24'

- name: Run go vet
run: go vet ./...

- name: Check formatting
run: |
unformatted=$(gofmt -l .)
if [ -n "$unformatted" ]; then
echo "The following files are not formatted:"
echo "$unformatted"
exit 1
fi
go-version-file: go.mod
- name: Check go.mod is tidy
run: go mod tidy -diff
- name: Lint
run: make lint

test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4

uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: '1.24'

- name: Run unit tests
go-version-file: go.mod
- name: Test
run: make test

- name: Run integration tests
run: make test-verify-verbose
vuln:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- name: Check for known vulnerabilities
run: make vuln

build:
runs-on: ubuntu-latest
strategy:
matrix:
goarch: [amd64, arm64]
steps:
- name: Checkout Code
uses: actions/checkout@v4

uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: '1.24'

go-version-file: go.mod
- name: Build Server
run: make build GOOS=linux GOARCH=${{ matrix.goarch }}
- name: Build Lambda
run: GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -C cmd/lambda -o ../../dist/bootstrap
run: make build-lambda GOARCH=${{ matrix.goarch }}

image:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Build Container Image
run: docker buildx build --platform linux/amd64,linux/arm64 --build-arg VERSION=ci .
52 changes: 47 additions & 5 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,64 @@ on:
permissions:
contents: write

concurrency:
group: release
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Bump Version
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
cache: false
# dry_run only computes the version; the release step creates the tag
# after the artifacts build, so a failed build leaves no tag behind
- name: Compute Version
id: tag_version
uses: mathieudutour/github-tag-action@v6.1
uses: mathieudutour/github-tag-action@af99e60ce8132224b8e6ebab5023449fe256ed46 # v7.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
dry_run: true
default_bump: minor
custom_release_rules: bug:patch:Fixes,chore:patch:Chores,docs:patch:Documentation,feat:minor:Features,refactor:minor:Refactors,test:patch:Tests,ci:patch:Development,dev:patch:Development
# a custom rule that matches a commit's type wins over the default
# "breaking change -> major" rule, so types that carry breaking
# changes (feat, fix, refactor) must not be listed here. feat and
# fix use the default rules, and refactor uses default_bump.
custom_release_rules: bug:patch:Fixes,chore:patch:Chores,docs:patch:Documentation,test:patch:Tests,ci:patch:Development,dev:patch:Development
- name: Build Artifacts
if: steps.tag_version.outputs.new_tag != ''
env:
VERSION: ${{ steps.tag_version.outputs.new_tag }}
run: |
mkdir -p release
for arch in amd64 arm64; do
make build GOOS=linux GOARCH="$arch" VERSION="$VERSION"
tar -czf "release/github-ops-app_linux_${arch}.tar.gz" -C dist github-ops-app
make build-lambda GOARCH="$arch" VERSION="$VERSION"
(cd dist && zip -X -q "../release/github-ops-app_lambda_${arch}.zip" bootstrap)
done
(cd release && sha256sum *.tar.gz *.zip > checksums.txt)
- name: Setup Buildx
if: steps.tag_version.outputs.new_tag != ''
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Build Container Image
if: steps.tag_version.outputs.new_tag != ''
env:
VERSION: ${{ steps.tag_version.outputs.new_tag }}
run: docker buildx build --platform linux/amd64,linux/arm64 --build-arg VERSION="$VERSION" .
- name: Create Release
uses: ncipollo/release-action@v1.12.0
if: steps.tag_version.outputs.new_tag != ''
uses: ncipollo/release-action@339a81892b84b4eeb0f6e744e4574d79d0d9b8dd # v1.21.0
with:
tag: ${{ steps.tag_version.outputs.new_tag }}
commit: ${{ github.sha }}
name: ${{ steps.tag_version.outputs.new_tag }}
body: ${{ steps.tag_version.outputs.changelog }}
artifacts: release/*
4 changes: 1 addition & 3 deletions .github/workflows/semantic-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ jobs:
name: Semantic Commit Message Check
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- uses: amannn/action-semantic-pull-request@v5.2.0
- uses: amannn/action-semantic-pull-request@2252a14e810aa9b85c2d560bd7070c802206ecf6 # v6.1.2
name: Check PR for Semantic Commit Message
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
Loading
Loading