diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37f5602..068f6b1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,57 +3,48 @@ name: Release on: push: branches: - - 'release/v[0-9]+.[0-9]+.*' - - paths: - - Payload_Type/thanatos/** - - config.json - - agent_capabilities.json + - main env: - IMAGE_REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - IMAGE_DESCRIPTION: "Base container image for the Thanatos Mythic C2 agent" - IMAGE_LICENSE: BSD-3-Clause - AGENT_CODE: Payload_Type/thanatos/thanatos/agent_code + # Registry for the container image + CONTAINER_IMAGE_REGISTRY: ghcr.io + # Name of the container image + CONTAINER_IMAGE_NAME: ${{ github.repository }} + # Description of the base container image + CONTAINER_IMAGE_DESCRIPTION: "Base container image for the Thanatos Mythic C2 agent" + # License for the base container image + CONTAINER_IMAGE_LICENSE: BSD-3-Clause + # Path to the agent code + AGENT_CODE_PATH: Payload_Type/thanatos/thanatos/agent_code jobs: - lint-workflow: - name: Lint - uses: ./.github/workflows/lint.yml - - build-container: - name: Build and push the base container image - needs: lint-workflow + # Get the new release version number + version: + name: Get the new release version runs-on: ubuntu-latest - permissions: - contents: read - packages: write + outputs: + release: ${{ steps.release.number }} steps: - name: Checkout the repository uses: actions/checkout@v4 - - name: Get the release version from the branch name + - name: Get the latest release version from the changelog + run: echo "RELEASE_VERSION=$(python .github/scripts/changelogtool.py latest)" >> $GITHUB_ENV + + - name: Verify that a tag with this version does not already exist run: | - GIT_BRANCH=${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}} - VERSION=$(echo $GIT_BRANCH | grep --color=never -Eo '[0-9]+\.[0-9]+\.[0-9]+') - echo "VERSION=$VERSION" >> $GITHUB_ENV + git tag -l | grep $RELEASE_VERSION + test $? -eq 0 && { echo "Tag for release $RELEASE_VERSION already exists"; exit 1 } || exit 0 - - name: Build and push the container - uses: ./.github/actions/build-container - with: - image-registry: ${{ env.IMAGE_REGISTRY }} - image-name: ${{ env.IMAGE_NAME }} - image-tag: v${{ env.VERSION }} - image-description: ${{ env.IMAGE_DESCRIPTION }} - image-license: ${{ env.IMAGE_LICENSE }} - github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Store the new release version number + id: release + run: echo "number=${RELEASE_VERSION#v}" >> $GITHUB_OUTPUT - version: + bump: name: Bump repository version numbers - needs: build-container + needs: version runs-on: ubuntu-latest permissions: @@ -64,43 +55,120 @@ jobs: - name: Checkout the repository uses: actions/checkout@v4 - - name: Get the release version from the branch name - run: | - GIT_BRANCH=${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}} - VERSION=$(echo $GIT_BRANCH | grep --color=never -Eo '[0-9]+\.[0-9]+\.[0-9]+') - echo "VERSION=$VERSION" >> $GITHUB_ENV - - name: Lowercase the container image name - run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV} + run: echo "CONTAINER_IMAGE_NAME=${CONTAINER_IMAGE_NAME,,}" >> ${GITHUB_ENV} - name: Set config.json version number uses: jossef/action-set-json-field@v2.1 with: file: config.json field: remote_images.thanatos - value: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:v${{ env.VERSION }} + value: ${{ env.CONTAINER_IMAGE_REGISTRY }}/${{ env.CONTAINER_IMAGE_NAME }}:v${{ needs.version.release }} - name: Set agent_capabilities.json version number uses: jossef/action-set-json-field@v2.1 with: file: agent_capabilities.json field: agent_version - value: ${{ env.VERSION }} + value: ${{ needs.version.release }} - - name: Set base Dockerfile image reference version number + - name: Set base Dockerfile image reference tag to match the version number working-directory: Payload_Type/thanatos - run: sed -i "s|^FROM ghcr\.io.*$|FROM ${IMAGE_REGISTRY}/${IMAGE_NAME}:v${VERSION}|" Dockerfile + env: + VERSION: ${{ needs.version.number }} + run: sed -i "s|^FROM .*$|FROM ${CONTAINER_IMAGE_REGISTRY}/${CONTAINER_IMAGE_NAME}:v${VERSION}|" Dockerfile - name: Set agent Cargo.toml version number - working-directory: ${{ env.AGENT_CODE }} + working-directory: ${{ env.AGENT_CODE_PATH }} + env: + VERSION: ${{ needs.version.number }} run: sed -i "0,/^version = .*$/s//version = \"${VERSION}\"/" Cargo.toml - name: Push the updated version number changes - uses: EndBug/add-and-commit@v9 # ref: https://github.com/marketplace/actions/add-commit + uses: EndBug/add-and-commit@v9 with: - add: "['config.json', 'agent_capabilities.json', 'Payload_Type/thanatos/Dockerfile', '${{ format(\'{0}/Cargo.toml\', env.AGENT_CODE) }}']" + add: "['config.json', 'agent_capabilities.json', 'Payload_Type/thanatos/Dockerfile', '${{ format('{0}/Cargo.toml', env.AGENT_CODE_PATH) }}']" default_author: github_actions committer_email: github-actions[bot]@users.noreply.github.com - message: "Bump version number to match release '${{ env.VERSION }}'" - new_branch: ${{ github.ref_name }} + message: "chore(release): bump version numbers to match release 'v${{ needs.version.release }}'" + pathspec_error_handling: exitImmediately + + image: + name: Build the base container image + needs: + - version + - bump + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + - name: Set the container image fully qualified url + run: echo "CONTAINER_IMAGE_URL=${CONTAINER_IMAGE_URL,,}" >> ${GITHUB_ENV} + env: + CONTAINER_IMAGE_URL: ${{ env.CONTAINER_IMAGE_REGISTRY }}/${{ env.CONTAINER_IMAGE_NAME }}:v${{ needs.version.release }} + + - name: Log in to the container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.CONTAINER_IMAGE_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push the container image + uses: docker/build-push-action@v5 + with: + context: Payload_Type/thanatos + file: Payload_Type/thanatos/.docker/Dockerfile + tags: ${{ env.CONTAINER_IMAGE_URL }} + push: true + labels: | + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.description=${{ env.CONTAINER_IMAGE_DESCRIPTION }} + org.opencontainers.image.licenses=${{ env.CONTAINER_IMAGE_LICENSE }} + + release: + name: Create a new release + needs: + - version + - image + runs-on: ubuntu-latest + + permissions: + contents: write + packages: read + + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + - name: Create a new tag for the release + uses: EndBug/add-and-commit@v9 + with: + message: "chore(release): Thanatos v${{ needs.version.release }}" + push: true + tag: "v${{ needs.version.release }}" pathspec_error_handling: exitImmediately + + - name: Create a new release + env: + VERSION: ${{ needs.version.release }} + run: | + RELEASE_BODY=$(python .github/scripts/changelogtool.py extract $VERSION) + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-Github-Api-Version: 2022-11-28" \ + /repos/${GITHUB_REPOSITORY}/releases \ + -f tag_name='v${VERSION}' \ + -f target_commitish="$GITHUB_REF_NAME" \ + -f name="Thanatos v${VERSION}" \ + -f body="$RELEASE_BODY" \ + -F draft=false \ + -F prerelease=false \ + -F generate_release_notes=false diff --git a/.github/workflows/verify-release.yml b/.github/workflows/verify-release.yml new file mode 100644 index 0000000..96e9e17 --- /dev/null +++ b/.github/workflows/verify-release.yml @@ -0,0 +1,32 @@ +name: Verify release + +on: + pull_request: + branches: + - main + +jobs: + verify: + name: Verify release PR + if: ${{ contains(github.event.pull_request.labels.*.name, "release") }} + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Get the latest changelog entry + run: echo "LATEST_CHANGELOG=$(python .github/scripts/changelogtool.py)" >> $GITHUB_ENV + + - name: Assert that a git tag does not exist for the latest entry + run: | + git tag -l | grep $LATEST_CHANGELOG + test $? -eq 0 && { echo "Git tag for changelog entry $LATEST_CHANGELOG already exists"; exit 1 } || exit 0 + + - name: Assert that a release does not already exist for the latest entry + run: | + gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-Github-Api-Version: 2022-11-28" \ + /repos/MythicAgents/thanatos/releases/tags/${LATEST_CHANGELOG} + test $? -eq 0 && { echo "Release for changelog entry $LATEST_CHANGELOG already exists"; exit 1 } || exit 0