From 3eeb0763a6fbe9304777eaea1bc03d7aaed568b0 Mon Sep 17 00:00:00 2001 From: LightHostingFree Date: Mon, 8 Jan 2024 12:20:57 +0530 Subject: [PATCH] created is-cool-me/dnscontrol-action --- .github/dependabot.yml | 12 +++ .github/workflows/build.yml | 20 ++++ CHANGELOG.md | 9 ++ Dockerfile | 34 +++++++ LICENSE.txt | 15 +++ README.md | 191 +++++++++++++++++++++++++++++++++++ action.yml | 25 +++++ bin/filter-preview-output.sh | 9 ++ entrypoint.sh | 45 +++++++++ examples/README.md | 7 ++ examples/deploy.yml | 21 ++++ examples/test.yml | 30 ++++++ 12 files changed, 418 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/build.yml create mode 100644 CHANGELOG.md create mode 100644 Dockerfile create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 action.yml create mode 100644 bin/filter-preview-output.sh create mode 100644 entrypoint.sh create mode 100644 examples/README.md create mode 100644 examples/deploy.yml create mode 100644 examples/test.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..4e0d2b6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..8dce285 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,20 @@ +--- +on: push +name: build +jobs: + test: + name: Run tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Dockerfilelint + uses: docker://replicated/dockerfilelint + with: + args: Dockerfile + + - name: ShellCheck + run: shellcheck entrypoint.sh + + - name: Build image + uses: docker/build-push-action@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4ec7437 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +## Unreleased + +## v3.3.0 + +- Add support for publishing the output of the 'preview' command as a comment to + the pull request. [\#26](https://github.com/koenrh/dnscontrol-action/pull/26) + ([@svenluijten](https://github.com/svenluijten)) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..194358e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +FROM alpine:3.18.5@sha256:d695c3de6fcd8cfe3a6222b0358425d40adfd129a8a47c3416faff1a8aece389 + +LABEL repository="https://github.com/is-cool-me/dnscontrol-action" +LABEL maintainer="light " + +LABEL "com.github.actions.name"="DNSControl" +LABEL "com.github.actions.description"="Deploy your DNS configuration to multiple providers." +LABEL "com.github.actions.icon"="cloud" +LABEL "com.github.actions.color"="yellow" + +ENV DNSCONTROL_VERSION="4.7.3" +ENV DNSCONTROL_CHECKSUM="f7825923bcc66e6758c9231ac42122322684cfa78aad2ae17ec4e772cd22c911" +ENV USER=dnscontrol-user + +RUN apk -U --no-cache upgrade && \ + apk add --no-cache bash ca-certificates curl libc6-compat tar + +RUN addgroup -S dnscontrol-user && adduser -S dnscontrol-user -G dnscontrol-user --disabled-password + +RUN curl -sL "https://github.com/StackExchange/dnscontrol/releases/download/v${DNSCONTROL_VERSION}/dnscontrol_${DNSCONTROL_VERSION}_linux_amd64.tar.gz" \ + -o dnscontrol && \ + echo "$DNSCONTROL_CHECKSUM dnscontrol" | sha256sum -c - && \ + tar xvf dnscontrol + +RUN chown dnscontrol-user:dnscontrol-user dnscontrol + +RUN chmod +x dnscontrol && \ + chmod 755 dnscontrol && \ + cp dnscontrol /usr/local/bin/dnscontrol + +RUN ["dnscontrol", "version"] + +COPY README.md entrypoint.sh bin/filter-preview-output.sh / +ENTRYPOINT ["/entrypoint.sh"] diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..53f9279 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2024, Light + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..50a205d --- /dev/null +++ b/README.md @@ -0,0 +1,191 @@ +# DNSControl Action + +![](https://github.com/koenrh/dnscontrol-action/workflows/build/badge.svg) + +Deploy your DNS configuration using [GitHub Actions](https://github.com/actions) +using [DNSControl](https://github.com/StackExchange/dnscontrol/). + +## Usage + +These are the three relevant sub commands to use with this action. + +### check + +Run the action with the 'check' argument in order to check and validate the `dnsconfig.js` +file. This action does not communicate with the DNS providers, hence does not require +any secrets to be set. + +```yaml +name: Check + +on: pull_request + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: DNSControl check + uses: koenrh/dnscontrol-action@v3 + with: + args: check + + # Optionally, if your DNSConfig files are in a non-default location, + # you could specify the paths to the config and credentials file. + config_file: 'dns/dnsconfig.js' +``` + +### preview + +Run the action with the 'preview' argument to check what changes need to be made. +It prints out what DNS records are expected to be created, modified or deleted. +This action requires the secrets for the specified DNS providers. + +```yaml +name: Preview + +on: pull_request + +jobs: + preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: DNSControl preview + uses: koenrh/dnscontrol-action@v3 + id: dnscontrol_preview + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + with: + args: preview + + # Optionally, if your DNSConfig files are in a non-default location, + # you could specify the paths to the config and credentials file. + config_file: 'dns/dnscontrol.js' + creds_file: 'dns/creds.json' +``` + +This is the action you probably want to run for each branch so that proposed changes +could be verified before an authorized person merges these changes into the default +branch. + +#### Pull request comment + +Optionally, you could configure your GitHub Action so that the output of the 'preview' +command is published as a comment to the pull request for the branch containing the +changes. This saves you several clicks through the menus to get to the output logs +for the preview job. + +``` + ******************** Domain: example.com +----- Getting nameservers from: cloudflare +----- DNS Provider: cloudflare...6 corrections +#1: CREATE record: @ TXT 1 v=spf1 include:_spf.google.com -all +#2: CREATE record: @ MX 1 1 aspmx.l.google.com. +#3: CREATE record: @ MX 1 5 alt1.aspmx.l.google.com. +#4: CREATE record: @ MX 1 5 alt2.aspmx.l.google.com. +#5: CREATE record: @ MX 1 10 alt3.aspmx.l.google.com. +#6: CREATE record: @ MX 1 10 alt4.aspmx.l.google.com. +----- Registrar: none...0 corrections +Done. 6 corrections. +``` + +Provided that your GitHub Action job for 'preview' has an id +`dnscontrol_preview`, you could use the following snippet to enable pull request +comments using Unsplash's [comment-on-pr](https://github.com/unsplash/comment-on-pr) +GitHub Action. + +```yaml +- name: Preview pull request comment + uses: unsplash/comment-on-pr@v1.3.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + msg: | + ``` + ${{ steps.dnscontrol_preview.outputs.preview_comment }} + ``` + check_for_duplicate_msg: true +``` + +### push + +Run the action with the 'push' argument to publish the changes to the specified +DNS providers. + +Running the action with the 'push' argument will publish the changes with the +specified DNS providers. The example workflow depicted below contains a filtering +pattern so that it only runs on the default branch. + +```yaml +name: Push + +on: + push: + branches: + - main + +jobs: + push: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: DNSControl push + uses: koenrh/dnscontrol-action@v3 + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + with: + args: push + + # Optionally, if your DNSConfig files are in a non-default location, + # you could specify the paths to the config and credentials file. + config_file: 'dns/dnsconfig.js' + creds_file: 'dns/creds.json' +``` + +## Credentials + +Depending on the DNS providers that are used, this action requires credentials to +be set. These secrets can be configured through a file named `creds.json`. You +should **not** add secrets as plaintext to this file, but use GitHub +Actions [encrypted secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) +instead. These encrypted secrets are exposed at runtime as environment variables. +See the DNSControl [Service Providers](https://stackexchange.github.io/dnscontrol/provider-list) +documentation for details. + +To follow the Cloudflare example, add an encrypted secret named `CLOUDFLARE_API_TOKEN` +and then define the `creds.json` file as follows. + +```json +{ + "cloudflare":{ + "TYPE": "CLOUDFLAREAPI", + "apitoken": "$CLOUDFLARE_API_TOKEN" + } +} +``` + +## Dependabot + +[Dependabot](https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-github-dependabot) +is a GitHub service that helps developers to automate dependency maintenance and +keep dependencies updated to the latest versions. It has native support for +[GitHub Actions](https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#package-ecosystem), +which means you can use it in your GitHub repository to keep the DNSConrol Acion +up-to-date. + +To enable Dependabot in your GitHub repository, add a `.github/dependabot.yml` +file with the following contents: + +```yaml +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" +``` diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..421e767 --- /dev/null +++ b/action.yml @@ -0,0 +1,25 @@ +--- +name: DNSControl Action +description: Deploy your DNS configuration to multiple providers +author: light +branding: + icon: cloud + color: yellow +inputs: + args: + description: DNSControl command + required: true + config_file: + description: Path to DNSControl configuration file. + required: false + default: 'dnsconfig.js' + creds_file: + description: Path to DNSControl credentials file. + required: false + default: 'creds.json' +outputs: + output: + description: The output of the dnscontrol command that was executed. +runs: + using: docker + image: 'Dockerfile' diff --git a/bin/filter-preview-output.sh b/bin/filter-preview-output.sh new file mode 100644 index 0000000..d7aa360 --- /dev/null +++ b/bin/filter-preview-output.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# source: https://git.io/J86QD +grep -v -e '^\.\.\.0 corrections$' |\ + grep -v -e '^0 corrections' |\ + grep -v -e '\.\.\. (skipping)' |\ + grep -v -e '^----- DNS Provider: ' |\ + grep -v -e '^----- Registrar: ' |\ + grep -v -e '^----- Getting nameservers from:' diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..8c09703 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +set -o pipefail + +# Resolve to full paths +CONFIG_ABS_PATH="$(readlink -f "${INPUT_CONFIG_FILE}")" +CREDS_ABS_PATH="$(readlink -f "${INPUT_CREDS_FILE}")" + +WORKING_DIR="$(dirname "${CONFIG_ABS_PATH}")" +cd "$WORKING_DIR" || exit + +ARGS=( + "$@" + --config "$CONFIG_ABS_PATH" +) + +# 'check' sub-command doesn't require credentials +if [ "$1" != "check" ]; then + ARGS+=(--creds "$CREDS_ABS_PATH") +fi + +IFS= +OUTPUT="$(dnscontrol "${ARGS[@]}")" +EXIT_CODE="$?" + +echo "$OUTPUT" + +# Filter output to reduce 'preview' PR comment length +FILTERED_OUTPUT="$(echo "$OUTPUT" | /filter-preview-output.sh)" + +# Set output +# https://github.com/orgs/community/discussions/26288#discussioncomment-3876281 +DELIMITER="DNSCONTROL-$RANDOM" + +{ + echo "output<<$DELIMITER" + echo "$OUTPUT" + echo "$DELIMITER" + + echo "preview_comment<<$DELIMITER" + echo "$FILTERED_OUTPUT" + echo "$DELIMITER" +} >> "$GITHUB_OUTPUT" + +exit $EXIT_CODE diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..dbea148 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,7 @@ +# Examples + +Find in this folder two GitHub Actions workflow examples. + +* [deploy.yml](deploy.yml): On merge into default branch, deploy the DNS changes. +* [test.yml](test.yml): Lint `dnsconfig.js` configuration file using ESLint, and + preview the DNS changes. diff --git a/examples/deploy.yml b/examples/deploy.yml new file mode 100644 index 0000000..03a58d2 --- /dev/null +++ b/examples/deploy.yml @@ -0,0 +1,21 @@ +--- +name: deploy + +on: + push: + branches: + - main + +jobs: + dnscontrol: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: DNSControl push + uses: koenrh/dnscontrol-action@v3 + env: + CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }} + CLOUDFLARE_API_USER: ${{ secrets.CLOUDFLARE_API_USER }} + with: + args: push diff --git a/examples/test.yml b/examples/test.yml new file mode 100644 index 0000000..abe80aa --- /dev/null +++ b/examples/test.yml @@ -0,0 +1,30 @@ +--- +name: Test + +on: pull_request + +jobs: + eslint: + name: ESLint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Run ESLint + uses: koenrh/actions/eslint@master + with: + args: dnsconfig.js + + dnscontrol: + name: DNSControl + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Preview + uses: koenrh/dnscontrol-action@v3 + env: + CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }} + CLOUDFLARE_API_USER: ${{ secrets.CLOUDFLARE_API_USER }} + with: + args: preview