-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[SHOT-231] Add scheduled seeded database workflow #8189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 39 commits
761fa3a
09f21b8
9afd95c
e5ea38d
a88d36a
c7640ee
5eb8d25
d178789
dc0e611
4ab6e4c
4d74615
b8a1ad4
c9cbff4
6202b7f
ad79e8d
bd808c7
2bb0d0b
aa929b3
459cf92
687c7b7
5d3aafa
261022c
d3a7536
466bc08
a12d900
1e3578a
f129486
9bcbb35
60681c8
fc25fdd
94ca593
3a72b11
8742f44
b2953f2
6279753
f514272
e0cc83e
53d3103
ee261fb
be6dcbc
e2f030f
d3c2e3e
f49055b
d3f2a31
7a97807
6a6c19b
ddb3e2a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,230 @@ | ||
| name: Build Seeded Database Images | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "0 2 * * 0" | ||
| workflow_dispatch: | ||
| inputs: | ||
| preset: | ||
| description: "Preset name to build (empty = curated default list, all = every preset)" | ||
| required: false | ||
| type: string | ||
| database: | ||
| description: "Database type to build (all = default matrix)" | ||
| required: false | ||
| default: all | ||
| type: choice | ||
| options: | ||
| - all | ||
| - postgres | ||
| - mysql | ||
| - mariadb | ||
| - mssql | ||
|
|
||
| env: | ||
| _AZ_REGISTRY: bitwardenprod.azurecr.io | ||
| _DEFAULT_PRESETS: >- | ||
| ["qa.dunder-mifflin-enterprise-full", | ||
| "scale.md-balanced-sterling-cooper", | ||
| "scale.lg-balanced-wayne-enterprises", | ||
| "scale.lg-highperm-tyrell-corp", | ||
| "scale.xl-broad-initech"] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
mimartin12 marked this conversation as resolved.
|
||
|
|
||
| jobs: | ||
| setup: | ||
| name: Determine build matrix | ||
| runs-on: ubuntu-22.04 | ||
| outputs: | ||
| presets: ${{ steps.matrix.outputs.presets }} | ||
| databases: ${{ steps.matrix.outputs.databases }} | ||
| steps: | ||
| - name: Check out repo | ||
| if: inputs.preset == 'all' | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Set up .NET | ||
| if: inputs.preset == 'all' | ||
| uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 | ||
| with: | ||
| cache: true | ||
| cache-dependency-path: "**/*.csproj" | ||
|
|
||
| - name: Build SeederUtility | ||
| if: inputs.preset == 'all' | ||
| run: dotnet build util/SeederUtility/SeederUtility.csproj | ||
|
|
||
| - name: Determine matrix | ||
| id: matrix | ||
| env: | ||
| INPUT_PRESET: ${{ inputs.preset }} | ||
| INPUT_DATABASE: ${{ inputs.database }} | ||
| run: | | ||
| if [[ "${INPUT_PRESET}" == "all" ]]; then | ||
| presets=$(dotnet run --project util/SeederUtility --no-build -- preset --list --output json \ | ||
| | jq -c '[.organization[], .individual[]]') | ||
| elif [[ -n "${INPUT_PRESET}" ]]; then | ||
| presets="[\"${INPUT_PRESET}\"]" | ||
| else | ||
| presets="${_DEFAULT_PRESETS}" | ||
| fi | ||
|
|
||
| if [[ -n "${INPUT_DATABASE}" && "${INPUT_DATABASE}" != "all" ]]; then | ||
| databases="[\"${INPUT_DATABASE}\"]" | ||
| else | ||
| databases='["postgres","mysql","mariadb","mssql"]' | ||
| fi | ||
|
|
||
| echo "presets=${presets}" >> "$GITHUB_OUTPUT" | ||
| echo "databases=${databases}" >> "$GITHUB_OUTPUT" | ||
| echo "Preset matrix: ${presets}" | ||
| echo "Database matrix: ${databases}" | ||
|
|
||
| build: | ||
| name: ${{ matrix.database }} / ${{ matrix.preset }} | ||
| needs: setup | ||
| runs-on: ubuntu-22.04 | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| strategy: | ||
| matrix: | ||
| preset: ${{ fromJson(needs.setup.outputs.presets) }} | ||
| database: ${{ fromJson(needs.setup.outputs.databases) }} | ||
| fail-fast: false | ||
|
|
||
| steps: | ||
| - name: Check out repo | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Set up .NET | ||
| uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 | ||
| with: | ||
| cache: true | ||
| cache-dependency-path: "**/*.csproj" | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 | ||
|
|
||
| - name: Set up QEMU | ||
| uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 | ||
|
|
||
| - name: Restore .NET local tools | ||
| run: dotnet tool restore | ||
|
|
||
| - name: Log in to Azure | ||
| uses: bitwarden/gh-actions/azure-login@main | ||
| with: | ||
| subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | ||
| tenant_id: ${{ secrets.AZURE_TENANT_ID }} | ||
| client_id: ${{ secrets.AZURE_CLIENT_ID }} | ||
|
|
||
| - name: Retrieve data protection key | ||
| id: retrieve-secret | ||
| uses: bitwarden/gh-actions/get-keyvault-secrets@main | ||
| with: | ||
| keyvault: gh-org-bitwarden | ||
| secrets: "DP-KEY-XML" | ||
|
|
||
| - name: Log out from Azure | ||
| uses: bitwarden/gh-actions/azure-logout@main | ||
|
|
||
| - name: Build seeded image | ||
| env: | ||
| PUSH: "false" | ||
| REGISTRY: ${{ env._AZ_REGISTRY }} | ||
| GIT_SHA: ${{ github.sha }} | ||
| MATRIX_PRESET: ${{ matrix.preset }} | ||
| MATRIX_DATABASE: ${{ matrix.database }} | ||
| DP_KEY_XML: ${{ steps.retrieve-secret.outputs.DP-KEY-XML }} | ||
| run: | | ||
| GIT_SHA="${GIT_SHA:0:7}" \ | ||
| bash util/SeederUtility/scripts/build-seeded-image.sh \ | ||
| "${MATRIX_PRESET}" \ | ||
| "${MATRIX_DATABASE}" | ||
|
|
||
| - name: Save image as tarball | ||
| env: | ||
| MATRIX_PRESET: ${{ matrix.preset }} | ||
| MATRIX_DATABASE: ${{ matrix.database }} | ||
| run: | | ||
| TAG="${MATRIX_PRESET//./-}" | ||
| DB="${MATRIX_DATABASE}" | ||
| SHA_SHORT="${GITHUB_SHA:0:7}" | ||
| docker save \ | ||
| "${_AZ_REGISTRY}/shot/seeded-${DB}:${TAG}-latest" \ | ||
| "${_AZ_REGISTRY}/shot/seeded-${DB}:${TAG}-${SHA_SHORT}" \ | ||
| -o "seeded-${DB}-${TAG}-${SHA_SHORT}.tar" | ||
|
|
||
| - name: Upload image artifact | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: seeded-${{ matrix.database }}-${{ matrix.preset }} | ||
| path: seeded-*.tar | ||
| retention-days: 7 | ||
| if-no-files-found: error | ||
|
|
||
| - name: Stage attachment blobs | ||
| run: | | ||
| mkdir -p bundle-out | ||
| for f in util/SeederUtility/docker/bundles/seeded-core-*.tar.gz; do | ||
| tar -xzf "${f}" -C bundle-out | ||
| done | ||
|
|
||
| - name: Upload attachment blobs | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: seeded-attachments-${{ matrix.database }}-${{ matrix.preset }} | ||
| path: bundle-out/core/attachments/** | ||
| retention-days: 7 | ||
| if-no-files-found: ignore | ||
|
|
||
| summary: | ||
| name: Image summary | ||
| needs: [setup, build] | ||
| if: always() | ||
| runs-on: ubuntu-22.04 | ||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| steps: | ||
| - name: Render image table | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| PRESETS: ${{ needs.setup.outputs.presets }} | ||
| DATABASES: ${{ needs.setup.outputs.databases }} | ||
| GIT_SHA: ${{ github.sha }} | ||
| run: | | ||
| SHA_SHORT="${GIT_SHA:0:7}" | ||
| results=$(gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/jobs" \ | ||
| --paginate --jq '.jobs[] | [.name, .conclusion] | @tsv') | ||
|
|
||
| { | ||
| echo "### Seeded images for \`${SHA_SHORT}\`" | ||
| echo "" | ||
| echo "| Preset | Database | Image |" | ||
| echo "| --- | --- | --- |" | ||
| while read -r db; do | ||
| while read -r preset; do | ||
| tag="${preset//./-}" | ||
| conclusion=$(printf '%s\n' "${results}" \ | ||
| | awk -F'\t' -v name="${db} / ${preset}" '$1 == name { print $2; exit }') | ||
| if [ "${conclusion}" != "success" ]; then | ||
| continue | ||
| fi | ||
| echo "| ${preset} | ${db} | \`${_AZ_REGISTRY}/shot/seeded-${db}:${tag}-${SHA_SHORT}\` |" | ||
| done < <(echo "${PRESETS}" | jq -r '.[]') | ||
| done < <(echo "${DATABASES}" | jq -r '.[]') | ||
| echo "" | ||
| echo "Images are built, not pushed. Download them from this run's artifacts." | ||
| } >> "$GITHUB_STEP_SUMMARY" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| docker/dp-keys/ | ||
| docker/licenses/ | ||
| docker/bundles/ | ||
| docker/seed.sql | ||
| docker/**/seed.sql | ||
| docker/**/seed.bak | ||
| docker/**/*.mdf | ||
| docker/**/*.ldf | ||
| docker/*/build/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| FROM mariadb:12 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. β Are all of these sufficiently covered by Renovate? Should you maybe add a grouping entry so this upgrades with the other(s)?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Covered by Renovate, yes, by default since Would the grouping happen automatically by Renovate? I would assume MariaDB, for example, would just get bumped in future PRs like this one. #7119 |
||
|
|
||
| ARG PRESET_NAME=unknown | ||
| ARG PRESET_CATEGORY=unknown | ||
| ARG GIT_SHA=unknown | ||
| ARG BUILD_DATE=unknown | ||
|
|
||
| LABEL bitwarden.seeder.preset="${PRESET_NAME}" | ||
| LABEL bitwarden.seeder.category="${PRESET_CATEGORY}" | ||
| LABEL org.opencontainers.image.revision="${GIT_SHA}" | ||
| LABEL org.opencontainers.image.created="${BUILD_DATE}" | ||
|
|
||
| ENV MARIADB_DATABASE=vault_dev | ||
| ENV MARIADB_ROOT_PASSWORD=Password1! | ||
|
|
||
| COPY seed.sql /docker-entrypoint-initdb.d/seed.sql | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| FROM mcr.microsoft.com/mssql/server:2025-CU5-ubuntu-24.04 | ||
|
|
||
| ARG PRESET_NAME=unknown | ||
| ARG PRESET_CATEGORY=unknown | ||
| ARG GIT_SHA=unknown | ||
| ARG BUILD_DATE=unknown | ||
|
|
||
| LABEL bitwarden.seeder.preset="${PRESET_NAME}" | ||
| LABEL bitwarden.seeder.category="${PRESET_CATEGORY}" | ||
| LABEL org.opencontainers.image.revision="${GIT_SHA}" | ||
| LABEL org.opencontainers.image.created="${BUILD_DATE}" | ||
|
|
||
| ENV ACCEPT_EULA=Y | ||
| ENV MSSQL_PID=Developer | ||
|
|
||
| USER root | ||
| RUN mkdir -p /seed | ||
| COPY vault_dev.mdf /seed/vault_dev.mdf | ||
| COPY vault_dev_log.ldf /seed/vault_dev_log.ldf | ||
| COPY docker-entrypoint.sh /docker-entrypoint.sh | ||
| RUN chmod +x /docker-entrypoint.sh | ||
|
|
||
| # Healthy only once the seed is attached, so dependents can wait on it rather than | ||
| # racing the attach and migrating an empty database into place | ||
| HEALTHCHECK --interval=10s --timeout=15s --retries=90 --start-period=30s \ | ||
| CMD /opt/mssql-tools18/bin/sqlcmd -S localhost -U SA -P "${SA_PASSWORD}" -C \ | ||
| -d vault -b -Q "SET NOCOUNT ON; SELECT TOP 1 1 FROM [User]" > /dev/null 2>&1 | ||
|
|
||
| ENTRYPOINT ["/docker-entrypoint.sh"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π¨ Given these hardcoded strings you may want to add a comment near their definition that this should also be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good callout, I added something in presets.md.
ddb3e2a