diff --git a/.github/haskell-ci.patch b/.github/haskell-ci.patch index 0728dab4..6c244f50 100644 --- a/.github/haskell-ci.patch +++ b/.github/haskell-ci.patch @@ -1,24 +1,26 @@ diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml -index d51bb64..7ff8684 100644 +index 96282c2..e40c573 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.github/workflows/haskell-ci.yml -@@ -224,3 +224,19 @@ jobs: - with: - key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} - path: ~/.cabal/store -+ - name: install executable -+ if: matrix.compiler == 'ghc-9.6.2' -+ run: | -+ $CABAL v2-install $ARG_COMPILER --install-method=copy exe:hsec-tools -+ - name: upload executable -+ uses: actions/upload-artifact@v3 -+ if: matrix.compiler == 'ghc-9.6.2' +@@ -19,6 +19,21 @@ + jobs: ++ tools_changed: ++ continue-on-error: true ++ runs-on: ubuntu-20.04 ++ outputs: ++ should_skip: ${{ steps.skip_check.outputs.should_skip }} ++ steps: ++ - id: skip_check ++ uses: fkirc/skip-duplicate-actions@v5.3.0 + with: -+ name: hsec-tools-${{ github.sha }} -+ path: ~/.cabal/bin/hsec-tools -+ check-advisories: -+ name: Invoke check-advisories workflow -+ needs: linux -+ uses: ./.github/workflows/check-advisories.yml -+ with: -+ artifact-name: hsec-tools-${{ github.sha }} ++ concurrent_skipping: "never" ++ skip_after_successful_duplicate: "true" ++ paths: '["code/**"]' ++ do_not_skip: '["push", "workflow_dispatch", "schedule"]' + linux: + name: Haskell-CI - Linux - ${{ matrix.compiler }} ++ needs: tools_changed ++ if: ${{ needs.tools_changed.outputs.should_skip != 'true' }} + runs-on: ubuntu-20.04 + timeout-minutes: + 60 diff --git a/.github/workflows/check-advisories-standalone.yml b/.github/workflows/check-advisories-standalone.yml new file mode 100644 index 00000000..563d138e --- /dev/null +++ b/.github/workflows/check-advisories-standalone.yml @@ -0,0 +1,69 @@ +name: Check advisories standalone +on: + - pull_request +jobs: + tools_changed: + continue-on-error: true + runs-on: ubuntu-22.04 + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5.3.0 + with: + concurrent_skipping: "never" + skip_after_successful_duplicate: "true" + paths: '["code/**"]' + do_not_skip: '["push", "workflow_dispatch", "schedule"]' + advisories_changed: + continue-on-error: true + runs-on: ubuntu-22.04 + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5.3.0 + with: + concurrent_skipping: "never" + skip_after_successful_duplicate: "true" + paths: '["advisories/**"]' + do_not_skip: '["push", "workflow_dispatch", "schedule"]' + code_hash: + name: Compute code directory hash + runs-on: ubuntu-22.04 + outputs: + code_hash: ${{ steps.code-hash.outputs.code-hash }} + steps: + - name: git checkout + uses: actions/checkout@v3 + - id: code-hash + run: | + code_hash=$(git rev-parse HEAD:code) + echo "code-hash=$code_hash" >> "$GITHUB_OUTPUT" + changed_files: + name: Debug + needs: [tools_changed, advisories_changed, code_hash] + if: ${{ needs.tools_changed.outputs.should_skip == 'true' && needs.advisories_changed.outputs.should_skip != 'true' }} + runs-on: ubuntu-22.04 + permissions: + pull-requests: read + outputs: + advisories: ${{ steps.changed-files.outputs.all_changed_files }} + steps: + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v37 + with: + json: "true" + + - name: List all changed files + run: echo "${{ steps.changed-files.outputs.all_changed_files }}" + check_advisories: + name: Invoke check-advisories workflow + needs: [tools_changed, advisories_changed, code_hash, changed_files] + if: ${{ needs.tools_changed.outputs.should_skip == 'true' && needs.advisories_changed.outputs.should_skip != 'true' }} + uses: ./.github/workflows/check-advisories.yml + with: + fetch-key: hsec-tools-${{ needs.code_hash.outputs.code_hash }} + is-artifact: false + changed-advisories: ${{ needs.changed_files.outputs.advisories }} diff --git a/.github/workflows/check-advisories.yml b/.github/workflows/check-advisories.yml index 2054ffb4..f524e367 100644 --- a/.github/workflows/check-advisories.yml +++ b/.github/workflows/check-advisories.yml @@ -2,9 +2,16 @@ name: Check and publish security advisories on: workflow_call: inputs: - artifact-name: + fetch-key: required: true type: string + is-artifact: + required: true + type: boolean + changed-advisories: + required: false + type: string + default: '[]' jobs: check-advisories: runs-on: ubuntu-20.04 @@ -15,23 +22,34 @@ jobs: # We need to retrieve full history to determine the correct # `published` and `modified` timestamps fetch-depth: 0 - - run: mkdir -p ~/.local/bin - - id: download + - run: mkdir -p ~/.local/dockerImages + - name: Fetch artifact + if: ${{ inputs.is-artifact }} uses: actions/download-artifact@v3 with: - name: ${{ inputs.artifact-name }} - path: ~/.local/bin - - run: chmod +x ~/.local/bin/hsec-tools + name: ${{ inputs.fetch-key }} + path: ~/.local/dockerImages + - name: Fetch cache + if: ${{ !inputs.is-artifact }} + uses: actions/cache/restore@v3 + with: + key: ${{ inputs.fetch-key }} + path: ~/.local/dockerImages + fail-on-cache-miss: true + - run: docker load -i ~/.local/dockerImages/hsec-tools + - name: 'Setup jq' + uses: dcarbone/install-jq-action@v1.0.1 - name: Run advisory syntax checks run: | + CHANGED_ADVISORIES=( $(echo "${{ inputs.changed-advisories }}" | jq -r '.[]') ) cd source RESULT=0 # Remove the begining of the README to extract the example. (echo '```toml'; sed -e '1,/```toml/d' README.md) > EXAMPLE_README.md while read FILE ; do echo -n "$FILE: " - hsec-tools check "$FILE" || RESULT=1 - done < <(find advisories EXAMPLE_README.md EXAMPLE_ADVISORY.md -type f -name "*.md") + docker run --rm -v $PWD:/advisories haskell/hsec-tools:latest /bin/hsec-tools check "advisories/$FILE" || RESULT=1 + done < <([ ${#CHANGED_ADVISORIES[@]} -gt 0 ] && echo $CHANGED_ADVISORIES || find advisories EXAMPLE_README.md EXAMPLE_ADVISORY.md -type f -name "*.md") exit $RESULT - name: Run advisory uniqueness checks run: | diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml index 90022731..8bcb9031 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.github/workflows/haskell-ci.yml @@ -17,8 +17,23 @@ on: - push - pull_request jobs: + tools_changed: + continue-on-error: true + runs-on: ubuntu-20.04 + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5.3.0 + with: + concurrent_skipping: "never" + skip_after_successful_duplicate: "true" + paths: '["code/**"]' + do_not_skip: '["push", "workflow_dispatch", "schedule"]' linux: name: Haskell-CI - Linux - ${{ matrix.compiler }} + needs: tools_changed + if: ${{ needs.tools_changed.outputs.should_skip != 'true' }} runs-on: ubuntu-20.04 timeout-minutes: 60 @@ -225,19 +240,3 @@ jobs: with: key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }} path: ~/.cabal/store - - name: install executable - if: matrix.compiler == 'ghc-9.6.2' - run: | - $CABAL v2-install $ARG_COMPILER --install-method=copy exe:hsec-tools - - name: upload executable - uses: actions/upload-artifact@v3 - if: matrix.compiler == 'ghc-9.6.2' - with: - name: hsec-tools-${{ github.sha }} - path: ~/.cabal/bin/hsec-tools - check-advisories: - name: Invoke check-advisories workflow - needs: linux - uses: ./.github/workflows/check-advisories.yml - with: - artifact-name: hsec-tools-${{ github.sha }} diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index e0ba92fd..7503f376 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -5,17 +5,64 @@ on: - push - pull_request jobs: + tools_changed: + continue-on-error: true + runs-on: ubuntu-22.04 + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5.3.0 + with: + concurrent_skipping: "never" + skip_after_successful_duplicate: "true" + paths: '["code/**"]' + do_not_skip: '["push", "workflow_dispatch", "schedule"]' check_nix: name: Check nix build + needs: tools_changed + if: ${{ needs.tools_changed.outputs.should_skip != 'true' }} runs-on: ubuntu-22.04 steps: - name: git checkout uses: actions/checkout@v3 - name: Install Nix uses: DeterminateSystems/nix-installer-action@main + with: + extra-conf: system-features = nixos-test benchmark big-parallel kvm + - uses: DeterminateSystems/magic-nix-cache-action@main - name: Check Nix flake inputs uses: DeterminateSystems/flake-checker-action@v4 with: flake-lock-path: ./code/hsec-tools/flake.lock - - run: nix -L build + - name: Build executable + run: nix -L build working-directory: ./code/hsec-tools + - name: Bild docker image + run: nix build -L '.#packages.x86_64-linux.hsec-tools-image' + working-directory: ./code/hsec-tools + - run: mkdir -p ~/.local/dockerImages + - run: cp code/hsec-tools/result ~/.local/dockerImages/hsec-tools + - id: code-hash + name: Compute code directory hash + run: | + code_hash=$(git rev-parse HEAD:code) + echo "code-hash=$code_hash" >> "$GITHUB_OUTPUT" + - uses: actions/cache/save@v3 + if: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + with: + key: hsec-tools-${{ steps.code-hash.outputs.code-hash}} + path: ~/.local/dockerImages + - name: upload executable + uses: actions/upload-artifact@v3 + with: + name: hsec-tools-${{ github.sha }} + path: ~/.local/dockerImages + check-advisories: + name: Invoke check-advisories workflow + if: ${{ needs.tools_changed.outputs.should_skip != 'true' }} + needs: check_nix + uses: ./.github/workflows/check-advisories.yml + with: + fetch-key: hsec-tools-${{ github.sha }} + is-artifact: true diff --git a/code/hsec-tools/flake.nix b/code/hsec-tools/flake.nix index 220f48db..7c6e465b 100644 --- a/code/hsec-tools/flake.nix +++ b/code/hsec-tools/flake.nix @@ -21,6 +21,7 @@ overrides = self: super: with pkgs.haskell.lib; { Cabal-syntax = super.Cabal-syntax_3_8_1_0; }; + modifier = drv: pkgs.haskell.lib.addBuildTools drv (with pkgs.haskellPackages; [ @@ -31,10 +32,53 @@ pkgs.nixpkgs-fmt ]); }; + + gitconfig = + pkgs.writeTextFile { + name = ".gitconfig"; + text = '' + [safe] + directory = * + ''; + destination = "/.gitconfig"; # should match 'config.WorkDir' + }; in { + + packages.hsec-tools = pkgs.haskell.lib.justStaticExecutables (project false); + packages.hsec-tools-image = + pkgs.dockerTools.buildImage { + name = "haskell/hsec-tools"; + tag = "latest"; + + copyToRoot = pkgs.buildEnv { + name = "image-root"; + paths = [ + self.packages.${system}.hsec-tools + pkgs.gitMinimal.out + gitconfig + ]; + pathsToLink = [ "/bin" "/" ]; + }; + runAsRoot = "rm -Rf /share"; + config = { + Cmd = [ "/bin/hsec-tools" ]; + Env = [ + "LOCALE_ARCHIVE=${pkgs.glibcLocalesUtf8}/lib/locale/locale-archive" + "LC_TIME=en_US.UTF-8" + "LANG=en_US.UTF-8" + "LANGUAGE=en" + "LC_ALL=en_US.UTF-8" + "GIT_DISCOVERY_ACROSS_FILESYSTEM=1" + ]; + Volumes = { + "/advisories" = { }; + }; + WorkDir = "/"; + }; + }; # Used by `nix build` & `nix run` (prod exe) - defaultPackage = project false; + defaultPackage = self.packages.${system}.hsec-tools; # Used by `nix develop` (dev shell) devShell = project true;