diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 0000000..7824e5d --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,62 @@ +name: Pull Request + +on: + pull_request: + +permissions: + contents: read + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + quickscope: + name: Quickscope + runs-on: ubuntu-latest + outputs: + result: ${{ steps.test.outputs.result }} + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + + - name: Build quickscope + working-directory: quickscope + run: docker build -t quickscope . + + - name: Run integration test + id: test + working-directory: quickscope + run: | + result=$(./integration.sh | tee /dev/stderr | tail -n1) + echo "result=$result" >> $GITHUB_OUTPUT + + - name: Upload diffs + if: ${{ steps.test.outputs.result == 'true' }} + uses: actions/upload-artifact@v4 + with: + name: quickscope-diffs + path: | + ./quickscope/integration/current.diff + ./quickscope/integration/new.diff + ./quickscope/integration/integration.diff + + comment: + name: Comment integration + needs: quickscope + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Post comment + env: + PR_C_REPO: ${{ github.repository }} + PR_C_NUMBER: ${{ github.event.pull_request.number }} + PR_C_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_QS_DIFF: ${{ needs.quickscope.outputs.result }} + run: .internal/ci/comment-integration.sh diff --git a/.gitignore b/.gitignore index d96fdb3..e905b75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,9 @@ KEYS env .env -*.swp \ No newline at end of file +*.swp + +# integration tests +new.diff +integration.diff +tmp/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..56613b0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/pentext"] + path = lib/pentext + url = https://github.com/radicallyopensecurity/pentext.git diff --git a/.internal/ci/comment-integration.sh b/.internal/ci/comment-integration.sh new file mode 100755 index 0000000..46c844b --- /dev/null +++ b/.internal/ci/comment-integration.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -e + +artifacts_url="https://api.github.com/repos/$PR_C_REPO/actions/runs/$GITHUB_RUN_ID/artifacts" +artifacts_json=$(curl -s -H "Authorization: token $PR_C_TOKEN" "$artifacts_url") + +diffs_id=$(echo "$artifacts_json" | jq -r '.artifacts[] | select(.name=="quickscope-diffs") | .id') +diffs_url="https://github.com/$PR_C_REPO/actions/runs/$GITHUB_RUN_ID/artifacts/$diffs_id" + +if [ "$PR_QS_DIFF" = "true" ]; then + body="**Quickscope:** Found diff. Please check the diffs: [download]($diffs_url)" +else + body="**Quickscope:** No diff found." +fi + +curl -s -H "Authorization: token $PR_C_TOKEN" \ + -H "Content-Type: application/json" \ + -d "$(jq -nc --arg body "$body" '{body: $body}')" \ + "https://api.github.com/repos/$PR_C_REPO/issues/$PR_C_NUMBER/comments" diff --git a/lib/pentext b/lib/pentext new file mode 160000 index 0000000..937354f --- /dev/null +++ b/lib/pentext @@ -0,0 +1 @@ +Subproject commit 937354f552956015fe471f8152a7fe00b0da461b diff --git a/quickscope/Dockerfile b/quickscope/Dockerfile index 77bebfb..0a7b19c 100644 --- a/quickscope/Dockerfile +++ b/quickscope/Dockerfile @@ -2,10 +2,11 @@ ARG SAXON_VERSION=10.9 # eclipse-temurin:21 tracks JDK 21, which is LTS -FROM eclipse-temurin:21-alpine as download-and-extract-tools +FROM eclipse-temurin:21-alpine AS download-and-extract-tools ARG SAXON_VERSION RUN wget https://repo1.maven.org/maven2/net/sf/saxon/Saxon-HE/${SAXON_VERSION}/Saxon-HE-${SAXON_VERSION}.jar + # use strict to force error exit code when jar is unsigned RUN jarsigner -verify -strict Saxon-HE-${SAXON_VERSION}.jar @@ -16,7 +17,6 @@ COPY --from=download-and-extract-tools /Saxon-HE-${SAXON_VERSION}.jar /saxon.jar RUN apk add --no-cache git -# add dummy fontconfig.properties to fix NPE -- https://github.com/AdoptOpenJDK/openjdk-build/issues/693 -ADD scripts/quickscope2off.sh /scripts/quickscope2off.sh +ADD src/quickscope2off.sh /usr/local/src/quickscope2off/quickscope2off.sh -ENTRYPOINT /scripts/quickscope2off.sh +ENTRYPOINT ["/usr/local/src/quickscope2off/quickscope2off.sh"] diff --git a/quickscope/README.md b/quickscope/README.md index e567606..eaccde8 100644 --- a/quickscope/README.md +++ b/quickscope/README.md @@ -1,3 +1,73 @@ -# quickscope +# quickscope2off -Convert quickscope into a quotation. \ No newline at end of file +Convert quickscope into a quotation. + +## Build + +```sh +docker build -t quickscope . +``` + +Run with: + +```sh +docker run \ + -e PROJECT_ACCESS_TOKEN="" + -e CI_PROJECT_URL="https://git.radicallyopensecurity.com//" \ + -e CI_PROJECT_ID="" \ + -e CI_SERVER_URL="https://git.radicallyopensecurity.com/" \ + --name convert \ + --rm \ + convert +``` + +## Development + +Create an `.env` file: + +```sh +PROJECT_ACCESS_TOKEN="" +COOKIE="_eyed_p_session=;" +``` + +```sh +docker run \ + --env-file ./.env + -e CI_PROJECT_URL="https://git.radicallyopensecurity.com//" \ + -e CI_PROJECT_ID="" \ + -e CI_SERVER_URL="https://git.radicallyopensecurity.com/" \ + --name convert \ + --rm \ + convert +``` + +## Test + +Make sure submodules are loaded and up to date: + +```sh +git submodule update --init +git submodule update +``` + +Make sure image is built: + +```sh +docker build -t quickscope . +``` + +```sh +./integration.sh +``` + +This will: + +- Create a copy of the `PenText` submodule which contains a sample quickscope report. +- Perform the conversion +- Compare the diff after conversion, with the currently committed diff +- Report differences + +It will output: + +- ./integration/new.diff => The diff after conversion +- ./integration/integration.diff => Diff between new diff and currently committed diff diff --git a/quickscope/integration.sh b/quickscope/integration.sh new file mode 100755 index 0000000..49969ca --- /dev/null +++ b/quickscope/integration.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +set -e + +GIT_USER=CI +GIT_PASS=dummy +REPO_NAME=test-remote.git + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/integration" + +TMPDIR="$SCRIPT_DIR/tmp" +REMOTE="$TMPDIR/remote" +SOURCE="$TMPDIR/source" + +echo "* Preparing tmp dirs" +rm -rf "$TMPDIR" +mkdir -p "$REMOTE" "$SOURCE" + +echo "* Cloning test repo into remote" +git -C "$SCRIPT_DIR/../../lib/pentext" \ + clone . "$REMOTE/$REPO_NAME" + +git -C "$REMOTE/$REPO_NAME" config http.receivepack true + +echo "* Starting git-http-backend container" +docker rm -f git-http-backend 2>/dev/null || true + +docker run -d --name git-http-backend \ + -v "$REMOTE":/git \ + ynohat/git-http-backend@sha256:b6f1e3e3cc06b8ae05fc22174808dfc3b4abd567cf8bc8c8bac311d83361b041 + +echo "* Running quickscope" +docker run --rm --name quickscope \ + --link git-http-backend \ + -e GIT_SSL_NO_VERIFY=true \ + -e SERVER_PROTOCOL=http \ + -e CI_PROJECT_DIR=/usr/local/src/repo \ + -e CI_SERVER_HOST=git-http-backend \ + -e CI_PROJECT_PATH=git/$REPO_NAME \ + -e CI_DEFAULT_BRANCH=main \ + -e PROJECT_ACCESS_TOKEN=$GIT_PASS \ + -v "$REMOTE/$REPO_NAME":/usr/local/src/repo \ + --entrypoint ash \ + quickscope:latest \ + -c "git config --global http.receivepack true && \ + git config --global --add safe.directory /usr/local/src/repo && \ + exec /usr/local/src/quickscope2off/quickscope2off.sh" + +echo "* Preparing for diff" +git -C "$SCRIPT_DIR/../../lib/pentext" \ + clone . "$SOURCE/$REPO_NAME" +docker exec -u 0 git-http-backend rm -rf "/git/$REPO_NAME/.git" +rm -rf "$SOURCE/$REPO_NAME/.git" + +echo "* Creating new diff" +diff -ruN "$SOURCE/$REPO_NAME" "$REMOTE/$REPO_NAME" \ + | sed -E 's/^(---|\+\+\+) ([^[:space:]]+).*/\1 \2/' \ + > "$SCRIPT_DIR/new.diff" + +echo "* Diffing with current" +diff -u \ + <(sed -E 's/date="[^"]+"/date="IGNORED"/' "$SCRIPT_DIR/current.diff" || true) \ + <(sed -E 's/date="[^"]+"/date="IGNORED"/' "$SCRIPT_DIR/new.diff" || true) \ + > "$SCRIPT_DIR/integration.diff" || test $? -eq 1 + +echo "* Cleaning up" +docker rm -f git-http-backend || true +rm -rf "$TMPDIR" + +echo "* Found diff?" +if [ -s "$SCRIPT_DIR/integration.diff" ]; then + echo "true" +else + echo "false" +fi diff --git a/quickscope/integration/current.diff b/quickscope/integration/current.diff new file mode 100644 index 0000000..e69de29 diff --git a/quickscope/scripts/quickscope2off.sh b/quickscope/src/quickscope2off.sh similarity index 64% rename from quickscope/scripts/quickscope2off.sh rename to quickscope/src/quickscope2off.sh index 4d10724..d809cc5 100755 --- a/quickscope/scripts/quickscope2off.sh +++ b/quickscope/src/quickscope2off.sh @@ -1,4 +1,5 @@ -#!/bin/sh +#!/usr/bin/env ash + set -e cd "$CI_PROJECT_DIR" @@ -11,6 +12,6 @@ git commit -m "convert pentext quickscope to offerte" git remote -v git remote rm origin -git remote add origin "https://CI:${PROJECT_ACCESS_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}" +git remote add origin "${SERVER_PROTOCOL:-https}://CI:${PROJECT_ACCESS_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}" -git push origin HEAD:${CI_DEFAULT_BRANCH} +git push origin HEAD:refs/heads/${CI_DEFAULT_BRANCH}