Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/run-coder-eval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,9 @@ jobs:
echo "${{ secrets.GH_PACKAGES_TOKEN || secrets.GH_PAT }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
docker pull "ghcr.io/uipath/coder-eval-agent:${CE_IMAGE_TAG}"

# Build the skills extension image (`@uipath/cli` + `@uipath/admin-tool`
# on top of coder-eval-agent). Matches smoke-skills.yml + daily.sh.
# Build the skills extension image (`@uipath/cli`, its tool plugins, and
# `@uipath/flow-sdk` on top of coder-eval-agent). Matches
# smoke-skills.yml + daily.sh.
- name: Build skills Docker image
env:
DOCKER_BUILDKIT: "1"
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/smoke-skills.yml
Original file line number Diff line number Diff line change
Expand Up @@ -366,12 +366,13 @@ jobs:
echo "${{ secrets.GH_PACKAGES_TOKEN || secrets.GH_PAT }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
docker pull ghcr.io/uipath/coder-eval-agent:${{ steps.ceref.outputs.version }}

# Build custom smoke image extending coder-eval-agent with @uipath/cli and
# every whitelisted tool plugin from GitHub Packages @dev (see
# tests/docker/Dockerfile). Every push to `cli/main` publishes a
# `-dev.<run>` prerelease under the `dev` dist-tag (cli PR #2650 renamed the
# old `alpha` tag → `dev` on 2026-06-26), so smoke tracks main — not stale
# `latest` from public npm (which lags by ~2 weeks).
# Build custom smoke image extending coder-eval-agent with @uipath/cli,
# every whitelisted tool plugin from GitHub Packages @dev, and the latest
# published @uipath/flow-sdk (see tests/docker/Dockerfile). Every push to
# `cli/main` publishes a `-dev.<run>` prerelease under the `dev` dist-tag
# (cli PR #2650 renamed the old `alpha` tag → `dev` on 2026-06-26), so
# smoke tracks main — not stale `latest` from public npm (which lags by ~2
# weeks).
- name: Build skills smoke Docker image
env:
DOCKER_BUILDKIT: "1"
Expand Down
46 changes: 44 additions & 2 deletions tests/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1.7
# Custom image for UiPath skills smoke tests
# Extends coder-eval-agent with UiPath CLI tools pre-installed
# Extends coder-eval-agent with UiPath CLI tools and the Flow SDK pre-installed
ARG CODER_EVAL_IMAGE=coder-eval-agent:latest
FROM ${CODER_EVAL_IMAGE}

Expand All @@ -17,6 +17,11 @@ ARG NPM_AUTH_TOKEN=
# and ETARGETs. A pin freezes the CLI; the tools ride the train's tag.
ARG CLI_VERSION=dev

# The builder SDK is released independently from the CLI. Follow its rolling
# release just as CLI_VERSION follows the live CLI train; callers can still
# override this with an exact version for a reproducible comparison.
ARG FLOW_SDK_VERSION=latest

# Floor on the number of tool plugins that must install for the image to be
# usable. Discovery returns the CLI's full whitelist; a few may lack a build on
# the current train (e.g. model-hub-tool has no `-dev` build), so individual
Expand All @@ -28,7 +33,10 @@ ARG MIN_TOOLS=25
# CLI, sync would try to re-align tools through the release-channel path (which
# can't resolve `-dev` tool builds — see below) and would undo the plugins baked
# here. Belt-and-suspenders with the eval harness env.
ENV UIPATH_CLI_DISABLE_VERSION_SYNC=1
ENV UIPATH_CLI_DISABLE_VERSION_SYNC=1 \
PREVIEW_FLOW_SDK_ROOT=/opt/preview-flow-sdk \
PREVIEW_FLOW_SDK_ASSETS_ROOT=/opt/preview-flow-sdk-assets \
UIP_MAESTRO_REGISTRY_HOME=/opt/preview-flow-sdk-assets/registry

# Install the UiPath CLI shell from its public npm release and pre-bake EVERY
# whitelisted tool plugin from GitHub Packages. Stable CLI releases such as the
Expand Down Expand Up @@ -95,6 +103,17 @@ RUN --mount=type=secret,id=npm_auth_token \
if [ "$public_cli" = false ]; then \
npm install -g "@uipath/cli@${CLI_VERSION}"; \
fi && \
mkdir -p "$PREVIEW_FLOW_SDK_ROOT" && \
printf '%s\n' '{"private":true,"type":"module"}' \
> "$PREVIEW_FLOW_SDK_ROOT/package.json" && \
npm install --prefix "$PREVIEW_FLOW_SDK_ROOT" \
--save-exact --no-audit --no-fund --userconfig "$npmrc" \
"@uipath/flow-sdk@${FLOW_SDK_VERSION}" && \
resolved_sdk_version="$(node -p \
"require('$PREVIEW_FLOW_SDK_ROOT/node_modules/@uipath/flow-sdk/package.json').version")" && \
printf '%s\n' "$resolved_sdk_version" > "$PREVIEW_FLOW_SDK_ROOT/flow-sdk.version" && \
echo "Installed @uipath/flow-sdk@${resolved_sdk_version}" && \
test -x "$PREVIEW_FLOW_SDK_ROOT/node_modules/.bin/flow-sdk" && \
uip --version && \
uip tools search --output json > /tmp/uip-tools-search.json && \
tools="$(grep -oE '@uipath/[a-z0-9-]+-tool' /tmp/uip-tools-search.json | sort -u || true)" && \
Expand Down Expand Up @@ -132,6 +151,29 @@ ENV DOTNET_ROOT=/usr/share/dotnet \
DOTNET_NOLOGO=1 \
DOTNET_CLI_TELEMETRY_OPTOUT=1

# Install the released connector catalog through the product CLI. The stable
# links keep the authoring paths independent of the catalog's content hash.
RUN cd "$PREVIEW_FLOW_SDK_ROOT" && \
uip maestro registry pull --force --output json && \
registry_snapshot="$(jq -er '.snapshotPath' "$UIP_MAESTRO_REGISTRY_HOME/current.json")" && \
test -f "$registry_snapshot/library-json/index.json" && \
test -f "$registry_snapshot/library-md/index.json" && \
mkdir -p "$PREVIEW_FLOW_SDK_ASSETS_ROOT" && \
ln -s "$registry_snapshot/library-json" "$PREVIEW_FLOW_SDK_ASSETS_ROOT/library-json" && \
ln -s "$registry_snapshot/library-md" "$PREVIEW_FLOW_SDK_ASSETS_ROOT/library-md" && \
ln -s "$registry_snapshot/connectors" "$PREVIEW_FLOW_SDK_ASSETS_ROOT/connectors"

ENV FLOW_SDK_LIBRARY_JSON=/opt/preview-flow-sdk-assets/library-json \
FLOW_SDK_LIBRARY_MD=/opt/preview-flow-sdk-assets/library-md \
FLOW_SDK_CONNECTORS_DIR=/opt/preview-flow-sdk-assets/connectors

# Prove that the installed SDK resolves without registry credentials and that
# the product CLI can check real source against it.
COPY tests/fixtures/maestro-flow-sdk-smoke/ /opt/maestro-flow-sdk-smoke/
RUN cd /opt/maestro-flow-sdk-smoke && \
ln -s ${PREVIEW_FLOW_SDK_ROOT}/node_modules node_modules && \
uip maestro flow check Smoke.flow.ts --source

# Pre-install Python packages needed by coded-agent sandbox fixtures so agents
# don't trigger a live uv-sync download (which takes 1-2 min and causes retry
# loops in the turn timeline). uipath-langchain is declared in the
Expand Down
73 changes: 0 additions & 73 deletions tests/docker/maestro-flow-sdk.Dockerfile

This file was deleted.

2 changes: 0 additions & 2 deletions tests/docker/maestro-flow-sdk.env

This file was deleted.

37 changes: 26 additions & 11 deletions tests/scripts/stage-preview-sdk-workspace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ set -euo pipefail
sdk_root=${PREVIEW_FLOW_SDK_ROOT:-/opt/preview-flow-sdk}
assets_root=${PREVIEW_FLOW_SDK_ASSETS_ROOT:-/opt/preview-flow-sdk-assets}
package_dir=$sdk_root/node_modules/@uipath/flow-sdk
library_json=${FLOW_SDK_LIBRARY_JSON:-$assets_root/typescript/sdk/lib/library-json}
library_json=${FLOW_SDK_LIBRARY_JSON:-$assets_root/library-json}
registry_root=${UIP_MAESTRO_REGISTRY_HOME:-$assets_root/registry}
registry_current=$registry_root/current.json

[[ -f "$package_dir/package.json" ]] || {
echo "stage-preview-sdk-workspace: missing $package_dir/package.json" >&2
Expand All @@ -18,10 +20,8 @@ library_json=${FLOW_SDK_LIBRARY_JSON:-$assets_root/typescript/sdk/lib/library-js
echo "stage-preview-sdk-workspace: missing connector library index at $library_json" >&2
exit 1
}

flow_builder_sdk_commit=$(tr -d '[:space:]' < "$assets_root/flow-builder-sdk.sha")
[[ -n "$flow_builder_sdk_commit" ]] || {
echo "stage-preview-sdk-workspace: missing flow-builder-sdk provenance" >&2
[[ -f "$registry_current" ]] || {
echo "stage-preview-sdk-workspace: missing connector registry provenance at $registry_current" >&2
exit 1
}

Expand All @@ -39,12 +39,27 @@ const fs = require('node:fs');
console.log(JSON.parse(fs.readFileSync(process.argv[2], 'utf8')).version);
NODE
)
sdk_gitref=$(node - "$package_dir/package.json" <<'NODE'
const fs = require('node:fs');
console.log(JSON.parse(fs.readFileSync(process.argv[2], 'utf8')).gitref || '');
NODE
)
registry_hash=$(node - "$registry_current" <<'NODE'
const fs = require('node:fs');
const {libraryHash} = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
if (typeof libraryHash !== 'string' || !libraryHash) {
throw new Error('connector registry provenance is missing libraryHash');
}
console.log(libraryHash);
NODE
)

ln -s "$sdk_root/node_modules" node_modules
node - "$sdk_version" "$flow_builder_sdk_commit" <<'NODE'
node - "$sdk_version" "$sdk_gitref" "$registry_hash" <<'NODE'
const fs = require('node:fs');
const version = process.argv[2];
const flowBuilderSdkCommit = process.argv[3];
const gitref = process.argv[3];
const connectorLibraryHash = process.argv[4];
let packageJson = {};
if (fs.existsSync('package.json')) {
packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
Expand All @@ -61,14 +76,14 @@ fs.writeFileSync(
`${JSON.stringify({
package: '@uipath/flow-sdk',
version,
flow_builder_sdk_commit: flowBuilderSdkCommit,
gitref: gitref || null,
connector_library: true,
connector_library_hash: connectorLibraryHash,
}, null, 2)}\n`,
);
NODE

node -e "import('@uipath/flow-sdk')"
uip maestro flow compile --help >/dev/null
prepare-connector --help >/dev/null
printf 'stage-preview-sdk-workspace: @uipath/flow-sdk@%s, flow-builder-sdk@%s, connector library\n' \
"$sdk_version" "$flow_builder_sdk_commit"
printf 'stage-preview-sdk-workspace: @uipath/flow-sdk@%s, connector library %s\n' \
"$sdk_version" "$registry_hash"
18 changes: 10 additions & 8 deletions tests/scripts/test_stage_preview_sdk_workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def test_stages_credential_free_sdk_workspace(tmp_path: Path) -> None:
{
"name": "@uipath/flow-sdk",
"version": "3.20.0",
"gitref": "efd27ce4c90ad76fc7f3c9b67f4920997b2cf0a8",
"type": "module",
"exports": "./index.js",
}
Expand All @@ -36,20 +37,19 @@ def test_stages_credential_free_sdk_workspace(tmp_path: Path) -> None:
(library_json / "index.json").write_text(
json.dumps({"entries": [{"nodeType": REQUIRED_CONNECTOR}]})
)
commit = "efd27ce4c90ad76fc7f3c9b67f4920997b2cf0a8"
(assets_root / "flow-builder-sdk.sha").write_text(f"{commit}\n")
registry_root = assets_root / "registry"
registry_root.mkdir()
registry_hash = "d34db33f"
(registry_root / "current.json").write_text(
json.dumps({"libraryHash": registry_hash})
)

bin_dir = tmp_path / "bin"
bin_dir.mkdir()
_write_executable(
bin_dir / "uip",
"#!/bin/sh\n[ \"$*\" = \"maestro flow compile --help\" ]\n",
)
_write_executable(
bin_dir / "prepare-connector",
"#!/bin/sh\n[ \"$*\" = \"--help\" ]\n",
)

workspace = tmp_path / "workspace"
workspace.mkdir()
(workspace / "package.json").write_text(
Expand All @@ -60,6 +60,7 @@ def test_stages_credential_free_sdk_workspace(tmp_path: Path) -> None:
"PATH": f"{bin_dir}:{os.environ['PATH']}",
"PREVIEW_FLOW_SDK_ROOT": str(sdk_root),
"PREVIEW_FLOW_SDK_ASSETS_ROOT": str(assets_root),
"UIP_MAESTRO_REGISTRY_HOME": str(registry_root),
"FLOW_SDK_LIBRARY_JSON": str(library_json),
}

Expand All @@ -82,6 +83,7 @@ def test_stages_credential_free_sdk_workspace(tmp_path: Path) -> None:
assert json.loads((workspace / "preview-sdk-provenance.json").read_text()) == {
"package": "@uipath/flow-sdk",
"version": "3.20.0",
"flow_builder_sdk_commit": commit,
"gitref": "efd27ce4c90ad76fc7f3c9b67f4920997b2cf0a8",
"connector_library": True,
"connector_library_hash": registry_hash,
}
Loading