From 0c69c06a2ba931daa2bf7a2af289a4071c071627 Mon Sep 17 00:00:00 2001 From: Fede Barcelona Date: Thu, 18 Jun 2026 10:52:44 +0200 Subject: [PATCH 1/4] ci: run workflows inside nix develop shell Pin the toolchain (node, typescript, tfx-cli, azure-cli, jq, pinact) in a flake devShell so CI and local builds share one reproducible environment instead of installing tools ad-hoc. tfx-cli is not in nixpkgs, so build it from upstream Microsoft/tfs-cli in nix/tfx-cli.nix. Workflows now install Nix and use `nix develop --command bash` as the default shell, dropping the manual node setup and `npm install -g` steps. Actions are pinned to commit SHAs via `make pin-actions` (pinact). --- .envrc | 4 ++ .github/workflows/ci-pull-request.yml | 23 +++++----- .github/workflows/main.yml | 27 ++++++------ .github/workflows/sync-versions.yml | 13 +++++- .gitignore | 4 +- Makefile | 5 ++- flake.lock | 61 +++++++++++++++++++++++++++ flake.nix | 45 ++++++++++++++++++++ nix/tfx-cli.nix | 30 +++++++++++++ 9 files changed, 183 insertions(+), 29 deletions(-) create mode 100644 .envrc create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/tfx-cli.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8d34452 --- /dev/null +++ b/.envrc @@ -0,0 +1,4 @@ +has nix && use flake +watch_file *.nix +dotenv_if_exists .env # You can create a .env file with your env vars for this project. You can also use .secrets if you are using act. See the line below. +dotenv_if_exists .secrets # Used by [act](https://nektosact.com/) to load secrets into the pipelines diff --git a/.github/workflows/ci-pull-request.yml b/.github/workflows/ci-pull-request.yml index acd66ec..6bd4154 100644 --- a/.github/workflows/ci-pull-request.yml +++ b/.github/workflows/ci-pull-request.yml @@ -13,22 +13,23 @@ permissions: jobs: build: runs-on: ubuntu-latest + defaults: + run: + shell: nix develop --command bash {0} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - name: Setup Node.js - uses: actions/setup-node@v2 - with: - node-version: '20.x' + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # v22 - - name: Install tfx-cli and typescript - run: | - npm install -g tfx-cli - npm install -g typescript + - name: Enable Nix cache + uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # v14 + with: + use-flakehub: false - name: Login to Azure DevOps - uses: azure/login@v2 + uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 with: client-id: ${{ secrets.AZURE_APPLICATION_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} @@ -44,5 +45,3 @@ jobs: - name: Build release run: | make build - - diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5c9f5af..7d12528 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,12 +18,23 @@ concurrency: jobs: build-and-release: runs-on: ubuntu-latest + defaults: + run: + shell: nix develop --command bash {0} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 # Need history to compare versions + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # v22 + + - name: Enable Nix cache + uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # v14 + with: + use-flakehub: false + - name: Check for version change id: check_version run: | @@ -41,21 +52,9 @@ jobs: echo "changed=false" >> $GITHUB_OUTPUT fi - - name: Setup Node.js - if: steps.check_version.outputs.changed == 'true' - uses: actions/setup-node@v2 - with: - node-version: '20.x' - - - name: Install tfx-cli and typescript - if: steps.check_version.outputs.changed == 'true' - run: | - npm install -g tfx-cli - npm install -g typescript - - name: Login to Azure DevOps if: steps.check_version.outputs.changed == 'true' - uses: azure/login@v1 + uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0 with: client-id: ${{ secrets.AZURE_APPLICATION_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} diff --git a/.github/workflows/sync-versions.yml b/.github/workflows/sync-versions.yml index 5b0fbdf..bf518c0 100644 --- a/.github/workflows/sync-versions.yml +++ b/.github/workflows/sync-versions.yml @@ -9,14 +9,25 @@ jobs: sync-versions: runs-on: ubuntu-latest if: contains(github.event.pull_request.labels.*.name, 'skip-version-sync') == false + defaults: + run: + shell: nix develop --command bash {0} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: ref: ${{ github.head_ref }} token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # v22 + + - name: Enable Nix cache + uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d # v14 + with: + use-flakehub: false + - name: Check for version change id: version_changed run: | diff --git a/.gitignore b/.gitignore index 051a6e3..d92ce8d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ node_modules/ output.html .npm id -local_text.txt \ No newline at end of file +local_text.txt +.direnv +result diff --git a/Makefile b/Makefile index 99ec1ac..d32e6c7 100644 --- a/Makefile +++ b/Makefile @@ -21,4 +21,7 @@ publish-release: tfx extension publish --manifest-globs $(HOME)/vss-extension.json --overrides-file $(HOME)/vss-extension-release.json \ --token $(AZURE_DEVOPS_ACCESS_TOKEN) -.PHONY: build publish +pin-actions: + pinact run -u + +.PHONY: build publish publish-local publish-release pin-actions diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..32dc9c3 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1781607440, + "narHash": "sha256-rxO+uc/KFbSJp+pgyXRuAX6QlG9hJdnt0BXpEQRXY+U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3e41b24abd260e8f71dbe2f5737d24122f972158", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..89775a8 --- /dev/null +++ b/flake.nix @@ -0,0 +1,45 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + outputs = + { + self, + nixpkgs, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + overlays = [ self.overlays.default ]; + }; + in + { + devShells.default = + with pkgs; + mkShell { + packages = [ + azure-cli + git + gnumake + jq + nodejs_22 + pinact + tfx-cli + typescript + ]; + }; + + formatter = pkgs.nixfmt-tree; + } + ) + // { + overlays.default = final: prev: { + tfx-cli = final.callPackage ./nix/tfx-cli.nix { }; + }; + }; +} diff --git a/nix/tfx-cli.nix b/nix/tfx-cli.nix new file mode 100644 index 0000000..e57abf9 --- /dev/null +++ b/nix/tfx-cli.nix @@ -0,0 +1,30 @@ +# tfx-cli is not packaged in nixpkgs; build it from the upstream +# Microsoft/tfs-cli repo so `tfx extension publish` is available. +{ + lib, + buildNpmPackage, + fetchFromGitHub, +}: +buildNpmPackage rec { + pname = "tfx-cli"; + version = "0.23.3"; + + src = fetchFromGitHub { + owner = "Microsoft"; + repo = "tfs-cli"; + rev = "3c12ccb53f3fd700224d0db4490ebc0613df0b7e"; + hash = "sha256-gnADqxXmaweeaDzV3BTwVzHGjm7qZ4/QNWpx60iJLJ8="; + }; + + npmDepsHash = "sha256-wZS8UZNmiuk68NKe8FJzHgqtY9Fs7oZEZALtuB6HRS0="; + + # `npm run build` is `tsc -p .`; postbuild copies the bin entrypoint. + npmBuildScript = "build"; + + meta = { + description = "Cross-platform CLI for Azure DevOps and Team Foundation Server"; + homepage = "https://github.com/Microsoft/tfs-cli"; + license = lib.licenses.mit; + mainProgram = "tfx"; + }; +} From e327356b589a84cdad8cce0f888c2b537d8857a6 Mon Sep 17 00:00:00 2001 From: Fede Barcelona Date: Thu, 18 Jun 2026 10:59:58 +0200 Subject: [PATCH 2/4] build: replace Makefile with justfile Use just as the command runner; add it to the devShell (replacing gnumake) and update workflows to call just build / just publish-release. --- .github/workflows/ci-pull-request.yml | 2 +- .github/workflows/main.yml | 4 ++-- Makefile | 27 ----------------------- flake.nix | 2 +- justfile | 31 +++++++++++++++++++++++++++ 5 files changed, 35 insertions(+), 31 deletions(-) delete mode 100644 Makefile create mode 100644 justfile diff --git a/.github/workflows/ci-pull-request.yml b/.github/workflows/ci-pull-request.yml index 6bd4154..3b1895a 100644 --- a/.github/workflows/ci-pull-request.yml +++ b/.github/workflows/ci-pull-request.yml @@ -44,4 +44,4 @@ jobs: - name: Build release run: | - make build + just build diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7d12528..4bbb925 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -69,14 +69,14 @@ jobs: - name: Build release if: steps.check_version.outputs.changed == 'true' run: | - make build + just build - name: Publish release if: steps.check_version.outputs.changed == 'true' env: AZURE_DEVOPS_ACCESS_TOKEN: ${{ env.AZURE_DEVOPS_ACCESS_TOKEN }} run: | - make publish-release + just publish-release - name: Create Git Tag if: steps.check_version.outputs.changed == 'true' diff --git a/Makefile b/Makefile deleted file mode 100644 index d32e6c7..0000000 --- a/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -HOME := $(CURDIR) -TYPESCRIPT_SOURCE := $(HOME)/sysdig-cli-scan-task/ -AZURE_DEVOPS_ACCESS_TOKEN ?= - -# Default target -all: build - -build: - npm install - cd $(TYPESCRIPT_SOURCE) && npm install && tsc - -publish-local: build - tfx extension publish \ - --manifest-globs vss-extension-test.json \ - --publisher IgorEulalio \ - --extension-id b52fe4a2-0476-4973-bc50-cc44e9032e11 \ - --share-with sysdigtest \ - --token $(AZURE_DEVOPS_ACCESS_TOKEN) - -publish-release: - tfx extension publish --manifest-globs $(HOME)/vss-extension.json --overrides-file $(HOME)/vss-extension-release.json \ - --token $(AZURE_DEVOPS_ACCESS_TOKEN) - -pin-actions: - pinact run -u - -.PHONY: build publish publish-local publish-release pin-actions diff --git a/flake.nix b/flake.nix index 89775a8..27cb4a1 100644 --- a/flake.nix +++ b/flake.nix @@ -25,8 +25,8 @@ packages = [ azure-cli git - gnumake jq + just nodejs_22 pinact tfx-cli diff --git a/justfile b/justfile new file mode 100644 index 0000000..cfcd652 --- /dev/null +++ b/justfile @@ -0,0 +1,31 @@ +typescript_source := justfile_directory() / "sysdig-cli-scan-task" +azure_devops_access_token := env_var_or_default("AZURE_DEVOPS_ACCESS_TOKEN", "") + +# List available recipes +default: + @just --list + +# Install deps and compile the TypeScript task +build: + npm install + cd {{typescript_source}} && npm install && tsc + +# Publish a test build shared with the sysdigtest org +publish-local: build + tfx extension publish \ + --manifest-globs vss-extension-test.json \ + --publisher IgorEulalio \ + --extension-id b52fe4a2-0476-4973-bc50-cc44e9032e11 \ + --share-with sysdigtest \ + --token {{azure_devops_access_token}} + +# Publish the release build to the marketplace +publish-release: + tfx extension publish \ + --manifest-globs {{justfile_directory()}}/vss-extension.json \ + --overrides-file {{justfile_directory()}}/vss-extension-release.json \ + --token {{azure_devops_access_token}} + +# Pin GitHub Actions to commit SHAs +pin-actions: + pinact run -u From 0cff0fff69427228518af703ea612bd9e9ee35b9 Mon Sep 17 00:00:00 2001 From: Fede Barcelona Date: Thu, 18 Jun 2026 11:09:51 +0200 Subject: [PATCH 3/4] build: add just update recipe to bump tooling Add curl/sd to the devShell and expose packages.tfx-cli. `just update` runs flake update, bumps tfx-cli to the latest upstream commit with recomputed hashes (update-tfx/rehash-tfx), and re-pins actions, each step wrapped in `nix develop --command` so it runs from a bare shell. --- flake.nix | 4 ++++ justfile | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/flake.nix b/flake.nix index 27cb4a1..9a4b15f 100644 --- a/flake.nix +++ b/flake.nix @@ -19,16 +19,20 @@ }; in { + packages.tfx-cli = pkgs.tfx-cli; + devShells.default = with pkgs; mkShell { packages = [ azure-cli + curl git jq just nodejs_22 pinact + sd tfx-cli typescript ]; diff --git a/justfile b/justfile index cfcd652..f5bb84a 100644 --- a/justfile +++ b/justfile @@ -29,3 +29,28 @@ publish-release: # Pin GitHub Actions to commit SHAs pin-actions: pinact run -u + +# Update everything: flake inputs, tfx-cli, and pinned actions +update: + nix flake update + nix develop --command just update-tfx + nix develop --command just pin-actions + +# Bump tfx-cli to the latest upstream commit and recompute its hashes +update-tfx: + #!/usr/bin/env bash + set -euo pipefail + rev="$(git ls-remote https://github.com/Microsoft/tfs-cli HEAD | cut -f1)" + version="$(curl -fsSL "https://raw.githubusercontent.com/Microsoft/tfs-cli/${rev}/package.json" | jq -r .version)" + sd 'rev = ".*";' "rev = \"${rev}\";" nix/tfx-cli.nix + sd 'version = ".*";' "version = \"${version}\";" nix/tfx-cli.nix + just rehash-tfx + echo "tfx-cli -> ${version} (${rev})" + +# Recompute the source and npm hashes in nix/tfx-cli.nix +rehash-tfx: + #!/usr/bin/env bash + set -euo pipefail + rehash() { sd "${1} = \".*\";" "${1} = \"\";" nix/tfx-cli.nix; h="$( (nix build -L --no-link .#tfx-cli || true) 2>&1 | sed -nE 's/.*got:[[:space:]]+([^ ]+).*/\1/p' | tail -1)"; [ -n "${h}" ] && sd "${1} = \"\";" "${1} = \"${h}\";" nix/tfx-cli.nix && echo "${1} -> ${h}"; } + rehash hash + rehash npmDepsHash From c90b2160ecd950ea21f93a551ed3efb8a8aacf5d Mon Sep 17 00:00:00 2001 From: Fede Barcelona Date: Thu, 18 Jun 2026 11:42:15 +0200 Subject: [PATCH 4/4] ci: address review feedback - gitignore .env/.secrets so the .envrc-suggested secret files can't be committed by the workflows' git add . - pin the token-retrieval steps to the runner's az (shell: bash) so the binary that reads ~/.azure matches the one azure/login wrote it with - fail loudly in rehash-tfx instead of leaving an empty hash on parse error --- .github/workflows/ci-pull-request.yml | 2 ++ .github/workflows/main.yml | 2 ++ .gitignore | 2 ++ justfile | 14 +++++++++++++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-pull-request.yml b/.github/workflows/ci-pull-request.yml index 3b1895a..1509b9c 100644 --- a/.github/workflows/ci-pull-request.yml +++ b/.github/workflows/ci-pull-request.yml @@ -37,6 +37,8 @@ jobs: - name: Get Azure DevOps access token id: devops_token + # Use the runner's az (the one azure/login authenticated), not the nixpkgs az. + shell: bash run: | TOKEN="$(az account get-access-token --resource "${{ secrets.AZURE_MARKETPLACE_ACCESS_SCOPE }}" --query accessToken -o tsv)" echo "::add-mask::$TOKEN" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4bbb925..7787f80 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,6 +63,8 @@ jobs: - name: Get Azure DevOps access token if: steps.check_version.outputs.changed == 'true' id: get_token + # Use the runner's az (the one azure/login authenticated), not the nixpkgs az. + shell: bash run: | echo "AZURE_DEVOPS_ACCESS_TOKEN=$(az account get-access-token --resource ${{ secrets.AZURE_MARKETPLACE_ACCESS_SCOPE }} --query accessToken -o tsv)" >> $GITHUB_ENV diff --git a/.gitignore b/.gitignore index d92ce8d..ddcc320 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ id local_text.txt .direnv result +.env +.secrets diff --git a/justfile b/justfile index f5bb84a..00a457a 100644 --- a/justfile +++ b/justfile @@ -51,6 +51,18 @@ update-tfx: rehash-tfx: #!/usr/bin/env bash set -euo pipefail - rehash() { sd "${1} = \".*\";" "${1} = \"\";" nix/tfx-cli.nix; h="$( (nix build -L --no-link .#tfx-cli || true) 2>&1 | sed -nE 's/.*got:[[:space:]]+([^ ]+).*/\1/p' | tail -1)"; [ -n "${h}" ] && sd "${1} = \"\";" "${1} = \"${h}\";" nix/tfx-cli.nix && echo "${1} -> ${h}"; } + rehash() { + local key="$1" old new + old="$(grep -oE "${key} = \"[^\"]*\"" nix/tfx-cli.nix | head -1)" + sd "${key} = \".*\";" "${key} = \"\";" nix/tfx-cli.nix + new="$( (nix build -L --no-link .#tfx-cli || true) 2>&1 | sed -nE 's/.*got:[[:space:]]+([^ ]+).*/\1/p' | tail -1)" + if [ -z "${new}" ]; then + sd "${key} = \".*\";" "${old};" nix/tfx-cli.nix + echo "error: could not parse a new ${key}; restored previous value" >&2 + exit 1 + fi + sd "${key} = \"\";" "${key} = \"${new}\";" nix/tfx-cli.nix + echo "${key} -> ${new}" + } rehash hash rehash npmDepsHash