Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a12c149
feat(api): implement admin/roles/audit/config routes (app-06)
jonathan-vella Feb 27, 2026
70a9035
docs: update session tracker β€” app-06 complete, 131/131 tests pass
jonathan-vella Feb 27, 2026
15ecdad
feat(api): implement admin, roles, audit, and config routes (app-06)
jonathan-vella Feb 27, 2026
6463b1a
feat(leaderboard): SSR page with auto-refresh, expandable rows, grade…
jonathan-vella Feb 27, 2026
3b26e15
docs: update session tracker for app-07 completion
jonathan-vella Feb 27, 2026
b27215d
style: format leaderboard components and app-08 prompt
jonathan-vella Feb 27, 2026
e01c32f
fix: add language tag to markdown code block in sync-issues prompt
jonathan-vella Feb 27, 2026
ea65645
feat(web): add dashboard pages, admin UI, and shared components
jonathan-vella Feb 27, 2026
cf50b3e
docs: update session tracker for app-08-dashboard completion
jonathan-vella Feb 27, 2026
abf2146
docs(prompts): update model reference in git-commit-push prompt
jonathan-vella Feb 27, 2026
1a92ad3
test(app-09): comprehensive test suite β€” 178 tests, 93% line coverage
jonathan-vella Feb 27, 2026
278d69b
docs: update session tracker for app-09 completion
jonathan-vella Feb 27, 2026
420262b
docs: doc-gardening β€” update quality scores and fix instruction count
jonathan-vella Feb 27, 2026
4b0447b
ci: complete CI/CD workflows with bicep validation, coverage, OIDC, a…
jonathan-vella Feb 27, 2026
092f2b0
docs: update session tracker β€” Phase E complete, app-10-ci-cd done
jonathan-vella Feb 27, 2026
ad84c5d
feat: enhance seed script + add test fixtures (Phase F1)
jonathan-vella Feb 27, 2026
823a0c5
docs: complete Phase F supporting artifacts
jonathan-vella Feb 27, 2026
7ed0d80
docs: formatting and style hygiene updates
jonathan-vella Feb 27, 2026
fb870d4
chore: sync with main β€” resolve add/add conflicts, keep Phase F artif…
jonathan-vella Feb 27, 2026
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
8 changes: 8 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ See `docs/hackops-user-guide.md` for the full walkthrough.
- Only use `gh` for operations that have no equivalent MCP write tool in the current environment.
- In devcontainers, do not run `gh auth` commands unless the user explicitly asks for CLI authentication troubleshooting.

## Key Docs

| Doc | Purpose |
| ---------------------------- | ------------------------------------- |
| `docs/testing-strategy.md` | Test pyramid, tools, coverage targets |
| `docs/security-checklist.md` | Security invariants consolidated |
| `docs/local-dev-guide.md` | Step-by-step local setup |

## Validation

```bash
Expand Down
77 changes: 64 additions & 13 deletions .github/workflows/hackops-ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# HackOps CI Workflow
# Validates the HackOps Next.js web application on PRs and pushes
# Validates the HackOps Next.js web application on PRs and pushes.
# Jobs: lint, type-check, test (with coverage), bicep-validate, build.

name: HackOps CI

Expand All @@ -9,13 +10,15 @@ on:
paths:
- "apps/web/**"
- "packages/shared/**"
- "infra/bicep/hackops/**"
- "package.json"
- "turbo.json"
push:
branches: [main]
paths:
- "apps/web/**"
- "packages/shared/**"
- "infra/bicep/hackops/**"
- "package.json"
- "turbo.json"
workflow_dispatch:
Expand All @@ -27,9 +30,12 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
NODE_VERSION: "22"

jobs:
lint:
name: Lint & Type Check
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
Expand All @@ -38,18 +44,34 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
node-version: ${{ env.NODE_VERSION }}
cache: "npm"

- name: Install dependencies
run: npm ci

- name: Type check
run: npm run type-check

- name: Lint
- name: Run ESLint
run: npm run --workspace @hackops/web lint

type-check:
name: Type Check
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"

- name: Install dependencies
run: npm ci

- name: Run tsc --noEmit
run: npm run type-check

test:
name: Test
runs-on: ubuntu-latest
Expand All @@ -60,38 +82,67 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
node-version: ${{ env.NODE_VERSION }}
cache: "npm"

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test
- name: Run tests with coverage
run: npm run test -- --coverage

- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: apps/web/coverage/
retention-days: 14

bicep-validate:
name: Bicep Validate
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Install Bicep CLI
run: |
curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64
chmod +x bicep
sudo mv bicep /usr/local/bin/bicep

- name: Bicep build
run: bicep build infra/bicep/hackops/main.bicep

- name: Bicep lint
run: bicep lint infra/bicep/hackops/main.bicep

build:
name: Build
runs-on: ubuntu-latest
needs: [lint, test]
needs: [lint, type-check, test, bicep-validate]
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "22"
node-version: ${{ env.NODE_VERSION }}
cache: "npm"

- name: Install dependencies
run: npm ci

- name: Build application
run: npm run build
env:
NEXT_TELEMETRY_DISABLED: 1

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: hackops-web-build
path: apps/web/.next/
path: apps/web/.next/standalone/
retention-days: 7
177 changes: 163 additions & 14 deletions .github/workflows/hackops-deploy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# HackOps Deploy Workflow
# Deploys the HackOps Next.js application to Azure App Service
# Requires AZURE_WEBAPP_NAME and Azure OIDC credentials configured as secrets
# Deploys the HackOps Next.js application to Azure App Service.
# - dev: auto-deploys on push to main (staging slot swap)
# - prod: manual dispatch with approval gate
#
# Prerequisites:
# 1. Azure AD app registration with federated credential for this repo
# 2. GitHub environments "dev" and "prod" configured with OIDC secrets
# 3. "prod" environment has required-reviewers protection rule
#
# OIDC setup (per environment):
# AZURE_CLIENT_ID β€” App registration client ID
# AZURE_TENANT_ID β€” Azure AD tenant ID
# AZURE_SUBSCRIPTION_ID β€” Target subscription ID
# AZURE_RESOURCE_GROUP β€” Target resource group (e.g. rg-hackops-us-dev)
# AZURE_WEBAPP_NAME β€” App Service name (e.g. app-hackops-dev)

name: HackOps Deploy

Expand All @@ -10,28 +23,34 @@ on:
branches: [main]
types: [completed]
workflow_dispatch:
inputs:
environment:
description: "Target environment"
required: true
type: choice
options:
- dev
- prod
default: dev

permissions:
id-token: write
contents: read

concurrency:
group: hackops-deploy-production
group: hackops-deploy-${{ github.event.inputs.environment || 'dev' }}
cancel-in-progress: false

env:
AZURE_WEBAPP_NAME: ${{ vars.AZURE_WEBAPP_NAME || 'app-hackops-prod' }}
NODE_VERSION: "22"

jobs:
deploy:
name: Deploy to Azure App Service
build-and-test:
name: Build & Test
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
environment:
name: production
url: https://${{ env.AZURE_WEBAPP_NAME }}.azurewebsites.net

if: >-
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
steps:
- name: Checkout repository
uses: actions/checkout@v6
Expand All @@ -45,20 +64,150 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test

- name: Build application
run: npm run build
env:
NEXT_TELEMETRY_DISABLED: 1

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: hackops-deploy-bundle
path: apps/web/.next/standalone/
retention-days: 3

deploy-dev:
name: Deploy to Dev
runs-on: ubuntu-latest
needs: build-and-test
if: >-
(github.event_name == 'workflow_run') ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'dev')
environment:
name: dev
url: https://${{ vars.AZURE_WEBAPP_NAME || 'app-hackops-dev' }}.azurewebsites.net
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: hackops-deploy-bundle
path: deploy-package

- name: Login to Azure (OIDC)
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Deploy to Azure App Service
- name: Deploy IaC (Bicep)
run: |
az deployment group create \
--resource-group "${{ vars.AZURE_RESOURCE_GROUP || 'rg-hackops-us-dev' }}" \
--template-file infra/bicep/hackops/main.bicep \
--parameters environment=dev projectName=hackops \
--mode Incremental \
--no-wait

- name: Deploy to staging slot
uses: azure/webapps-deploy@v3
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
package: apps/web/.next/standalone
app-name: ${{ vars.AZURE_WEBAPP_NAME || 'app-hackops-dev' }}
slot-name: staging
package: deploy-package

- name: Swap staging to production slot
run: |
az webapp deployment slot swap \
--resource-group "${{ vars.AZURE_RESOURCE_GROUP || 'rg-hackops-us-dev' }}" \
--name "${{ vars.AZURE_WEBAPP_NAME || 'app-hackops-dev' }}" \
--slot staging \
--target-slot production

- name: Verify deployment health
run: |
HEALTH_URL="https://${{ vars.AZURE_WEBAPP_NAME || 'app-hackops-dev' }}.azurewebsites.net/api/health"
echo "Checking health at $HEALTH_URL ..."
for i in 1 2 3 4 5; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_URL" || echo "000")
if [ "$STATUS" = "200" ]; then
echo "Health check passed (attempt $i)"
exit 0
fi
echo "Attempt $i: status $STATUS β€” retrying in 15s..."
sleep 15
done
echo "Health check failed after 5 attempts"
exit 1

deploy-prod:
name: Deploy to Prod
runs-on: ubuntu-latest
needs: build-and-test
if: >-
github.event_name == 'workflow_dispatch' &&
github.event.inputs.environment == 'prod'
environment:
name: prod
url: https://${{ vars.AZURE_WEBAPP_NAME || 'app-hackops-prod' }}.azurewebsites.net
steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: hackops-deploy-bundle
path: deploy-package

- name: Login to Azure (OIDC)
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Deploy IaC (Bicep)
run: |
az deployment group create \
--resource-group "${{ vars.AZURE_RESOURCE_GROUP }}" \
--template-file infra/bicep/hackops/main.bicep \
--parameters environment=prod projectName=hackops \
--mode Incremental

- name: Deploy to staging slot
uses: azure/webapps-deploy@v3
with:
app-name: ${{ vars.AZURE_WEBAPP_NAME }}
slot-name: staging
package: deploy-package

- name: Swap staging to production slot
run: |
az webapp deployment slot swap \
--resource-group "${{ vars.AZURE_RESOURCE_GROUP }}" \
--name "${{ vars.AZURE_WEBAPP_NAME }}" \
--slot staging \
--target-slot production

- name: Verify deployment health
run: |
HEALTH_URL="https://${{ vars.AZURE_WEBAPP_NAME }}.azurewebsites.net/api/health"
echo "Checking health at $HEALTH_URL ..."
for i in 1 2 3 4 5; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_URL" || echo "000")
if [ "$STATUS" = "200" ]; then
echo "Health check passed (attempt $i)"
exit 0
fi
echo "Attempt $i: status $STATUS β€” retrying in 15s..."
sleep 15
done
echo "Health check failed after 5 attempts"
exit 1
Loading
Loading