diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5da0fab --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,5 @@ +version: 2 +updates: + - {package-ecosystem: nuget, directory: /, schedule: {interval: weekly}} + - {package-ecosystem: docker, directory: /, schedule: {interval: weekly}} + - {package-ecosystem: github-actions, directory: /, schedule: {interval: weekly}} diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index d57d659..aea8ea6 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -9,7 +9,7 @@ on: environment: {description: Canal a promover, required: true, type: choice, options: [staging, production]} permissions: {contents: read} concurrency: - group: pipeline-${{ github.repository }}-${{ inputs.environment || github.ref }} + group: pipeline-${{ github.repository }}-${{ inputs.environment || github.ref_name }} cancel-in-progress: ${{ (inputs.environment || github.ref_name) != 'production' }} jobs: ci: @@ -18,7 +18,9 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: {fetch-depth: 0} - - uses: gitleaks/gitleaks-action@dcedce43c6f43de0b836d1fe38946645c9c638dc # v2 + - run: docker run --rm -v "${{ github.workspace }}:/repo" zricethezav/gitleaks:v8.28.0 dir /repo --redact + env: + GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} - uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4 with: {dotnet-version: 10.0.x} - run: dotnet restore Lightcode.Registration.slnx @@ -55,6 +57,10 @@ jobs: org.opencontainers.image.revision=${{ github.sha }} cache-from: type=gha,scope=${{ matrix.image }} cache-to: type=gha,mode=max,scope=${{ matrix.image }} + - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: {image-ref: "ghcr.io/lightcode-team/${{ matrix.image }}:sha-${{ github.sha }}", vuln-type: "os,library", severity: "HIGH,CRITICAL", ignore-unfixed: true, exit-code: "1"} + - uses: anchore/sbom-action@df80a981bc6edbc4e220a492d3cbe9f5547a6e75 # v0.17.9 + with: {image: "ghcr.io/lightcode-team/${{ matrix.image }}:sha-${{ github.sha }}", artifact-name: "${{ matrix.image }}-sbom.spdx.json"} promote: needs: publish if: github.ref_name == 'develop' || github.event_name == 'workflow_dispatch' @@ -64,7 +70,14 @@ jobs: outputs: {channel: "${{ steps.channel.outputs.value }}"} steps: - id: channel - run: echo "value=${{ inputs.environment || 'staging' }}" >> "$GITHUB_OUTPUT" + shell: bash + run: | + set -euo pipefail + value="${{ inputs.environment }}" + if [[ -z "$value" ]]; then value=staging; fi + if [[ "$value" == "production" && "$GITHUB_REF_NAME" != "main" ]]; then echo "production can only be promoted from main" >&2; exit 1; fi + if [[ "$value" == "staging" && "$GITHUB_REF_NAME" != "develop" ]]; then echo "staging can only be promoted from develop" >&2; exit 1; fi + echo "value=$value" >> "$GITHUB_OUTPUT" - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 with: {registry: ghcr.io, username: "${{ github.actor }}", password: "${{ secrets.GITHUB_TOKEN }}"} @@ -72,6 +85,7 @@ jobs: CHANNEL: ${{ steps.channel.outputs.value }} SHA: ${{ github.sha }} run: | + set -euo pipefail for image in lightcode-registration-api lightcode-registration-email-api lightcode-registration-storage-api lightcode-registration-worker; do docker buildx imagetools create -t "ghcr.io/lightcode-team/$image:$CHANNEL" "ghcr.io/lightcode-team/$image:sha-$SHA" done @@ -79,8 +93,9 @@ jobs: needs: promote runs-on: ubuntu-latest timeout-minutes: 10 - environment: {name: "${{ needs.promote.outputs.channel }}", url: "${{ vars.DEPLOYMENT_URL }}"} steps: - env: {COOLIFY_WEBHOOK: "${{ secrets.COOLIFY_WEBHOOK }}", COOLIFY_TOKEN: "${{ secrets.COOLIFY_TOKEN }}"} - run: >- + run: | + set -euo pipefail + if [[ -z "$COOLIFY_WEBHOOK" || -z "$COOLIFY_TOKEN" ]]; then echo "Coolify is not configured yet; skipping deploy trigger."; exit 0; fi curl --fail-with-body --retry 3 -H "Authorization: Bearer $COOLIFY_TOKEN" "$COOLIFY_WEBHOOK" diff --git a/.github/workflows/rollback.yml b/.github/workflows/rollback.yml new file mode 100644 index 0000000..4ece82d --- /dev/null +++ b/.github/workflows/rollback.yml @@ -0,0 +1,33 @@ +name: rollback-ghcr +on: + workflow_dispatch: + inputs: + environment: {description: Canal a reapontar, required: true, type: choice, options: [staging, production]} + sha: {description: Commit SHA publicado como sha-, required: true, type: string} +permissions: {contents: read, packages: write} +concurrency: {group: "rollback-${{ github.repository }}-${{ inputs.environment }}", cancel-in-progress: false} +jobs: + rollback: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - shell: bash + run: | + set -euo pipefail + if [[ "${{ inputs.environment }}" == "production" && "$GITHUB_REF_NAME" != "main" ]]; then echo "production rollback must run from main" >&2; exit 1; fi + if [[ "${{ inputs.environment }}" == "staging" && "$GITHUB_REF_NAME" != "develop" ]]; then echo "staging rollback must run from develop" >&2; exit 1; fi + - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + with: {registry: ghcr.io, username: "${{ github.actor }}", password: "${{ secrets.GITHUB_TOKEN }}"} + - shell: bash + run: | + set -euo pipefail + for image in lightcode-registration-api lightcode-registration-email-api lightcode-registration-storage-api lightcode-registration-worker; do + docker buildx imagetools inspect "ghcr.io/lightcode-team/$image:sha-${{ inputs.sha }}" + docker buildx imagetools create -t "ghcr.io/lightcode-team/$image:${{ inputs.environment }}" "ghcr.io/lightcode-team/$image:sha-${{ inputs.sha }}" + done + - env: {COOLIFY_WEBHOOK: "${{ secrets.COOLIFY_WEBHOOK }}", COOLIFY_TOKEN: "${{ secrets.COOLIFY_TOKEN }}"} + run: | + set -euo pipefail + if [[ -z "$COOLIFY_WEBHOOK" || -z "$COOLIFY_TOKEN" ]]; then echo "Coolify is not configured yet; skipping deploy trigger."; exit 0; fi + curl --fail-with-body --retry 3 -H "Authorization: Bearer $COOLIFY_TOKEN" "$COOLIFY_WEBHOOK"