Skip to content
Draft
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
188 changes: 188 additions & 0 deletions .github/workflows/cli-smoke-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
name: CLI Smoke Test

on:
schedule:
# 3:30 UTC = 9:00 AM IST, daily
- cron: '30 3 * * *'
workflow_dispatch: {} # manual trigger for testing

permissions: {}

env:
NODE_VERSION: "20"
ALPHA_AUTHORITY: https://alpha.uipath.com
ORG: popoc
TENANT: adetenant
FOLDER_KEY: 8645d674-92d8-4281-9aef-43f3e3608ded
Comment on lines +14 to +16

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three values are hardcoded in the workflow file and will be committed to git history. ORG and TENANT expose internal alpha-environment infrastructure details; FOLDER_KEY is a GUID that could be used to make API calls in the wrong environment if reused elsewhere.

Use repository variables instead so they can be rotated/changed without a code commit:

Suggested change
ORG: popoc
TENANT: adetenant
FOLDER_KEY: 8645d674-92d8-4281-9aef-43f3e3608ded
ORG: ${{ vars.SMOKE_TEST_ORG }}
TENANT: ${{ vars.SMOKE_TEST_TENANT }}
FOLDER_KEY: ${{ vars.SMOKE_TEST_FOLDER_KEY }}

LOGIN_SCOPE: "Apps OR.Folders.Read OR.Execution"

jobs:
stable-cli:
name: Stable CLI (npm @latest)
runs-on: ubuntu-latest

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither stable-cli nor alpha-cli sets timeout-minutes. GitHub's default is 6 hours, so a hung uip codedapp deploy, uip codedapp publish, or network stall will silently occupy a runner until the run is force-cancelled — which could pile up for a daily workflow. Add a reasonable upper bound (30 minutes covers the full lifecycle with headroom):

Suggested change
runs-on: ubuntu-latest
runs-on: ubuntu-latest
timeout-minutes: 30

Same addition needed for the alpha-cli job at its runs-on line.

permissions:
contents: read
env:
# Unique per run — always a fresh publish + deploy, no collisions
APP_NAME: smoke-s-${{ github.run_number }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install CLI (npm @latest)
run: |
npm i -g @uipath/cli@latest
uip tools install codedapp
echo "CLI version: $(uip --version)"
uip tools list

- name: Login
env:
UIPATH_CLIENT_ID: ${{ secrets.UIPATH_CLIENT_ID }}
UIPATH_CLIENT_SECRET: ${{ secrets.UIPATH_CLIENT_SECRET }}
run: |
uip login \
--authority "${{ env.ALPHA_AUTHORITY }}" \
--organization "${{ env.ORG }}" \
--tenant "${{ env.TENANT }}" \
--client-id "$UIPATH_CLIENT_ID" \
--client-secret "$UIPATH_CLIENT_SECRET" \
--scope "${{ env.LOGIN_SCOPE }}"

- name: Pack
run: |
uip codedapp pack \
fixtures/smoke-test-app \
--name "$APP_NAME" \
--version "1.0.0"

- name: Publish
run: |
uip codedapp publish --name "$APP_NAME"

- name: Deploy

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow deploys an app to the alpha environment on every run but never cleans it up. Daily runs will accumulate deployed versions indefinitely. Add an explicit cleanup step that runs even on failure — either a dedicated uip codedapp undeploy step after health-check, or an if: always() cleanup job that runs after the test jobs.

Example (add as the last step in each job):

      - name: Cleanup
        if: always()
        run: |
          uip codedapp undeploy \
            --name "$APP_NAME" \
            --folder-key "${{ env.FOLDER_KEY }}" || true

run: |
uip codedapp deploy \
--name "$APP_NAME" \
--folder-key "${{ env.FOLDER_KEY }}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deploy step doesn't pin --version "$VERSION", so the CLI will deploy whatever it considers the "latest" published version. Today this is harmless because both jobs publish the same date-based version string. But once the version-collision fix (seconds-precision, separate open thread) lands, each job will publish a unique version. If a second run's Publish step completes between this run's Publish and Deploy steps, this job silently deploys the wrong version — and the health-check passes, masking the regression the pipeline is supposed to catch.

Pin the version to match what was just published:

Suggested change
--folder-key "${{ env.FOLDER_KEY }}"
--folder-key "${{ env.FOLDER_KEY }}" \
--version "$VERSION"

Same fix is needed in the alpha-cli job's Deploy step.


- name: Health check
run: |
APP_URL="https://${{ env.ORG }}.uipath.host/${APP_NAME}"
echo "Checking $APP_URL"
for i in 1 2 3; do
if curl -sf --max-time 10 "$APP_URL" > /dev/null; then
echo "Health check passed on attempt $i"
exit 0
fi
echo "Attempt $i failed, retrying in 10s..."
sleep 10
done
echo "Health check failed after 3 attempts"
exit 1

alpha-cli:
name: Alpha CLI (GH Packages)
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
env:
APP_NAME: smoke-a-${{ github.run_number }}
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Install CLI (GH Packages)
run: |
echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> ~/.npmrc
Comment thread
Raina451 marked this conversation as resolved.
echo "@uipath:registry=https://npm.pkg.github.com" >> ~/.npmrc
npm i -g @uipath/cli
uip tools install codedapp
echo "CLI version: $(uip --version)"
uip tools list

- name: Login
env:
UIPATH_CLIENT_ID: ${{ secrets.UIPATH_CLIENT_ID }}
UIPATH_CLIENT_SECRET: ${{ secrets.UIPATH_CLIENT_SECRET }}
run: |
uip login \
--authority "${{ env.ALPHA_AUTHORITY }}" \
--organization "${{ env.ORG }}" \
--tenant "${{ env.TENANT }}" \
--client-id "$UIPATH_CLIENT_ID" \
--client-secret "$UIPATH_CLIENT_SECRET" \
--scope "${{ env.LOGIN_SCOPE }}"

- name: Pack
run: |
uip codedapp pack \
fixtures/smoke-test-app \
--name "$APP_NAME" \
--version "1.0.0"

- name: Publish
run: |
uip codedapp publish --name "$APP_NAME"

- name: Deploy
run: |
uip codedapp deploy \
--name "$APP_NAME" \
--folder-key "${{ env.FOLDER_KEY }}"

- name: Health check
run: |
APP_URL="https://${{ env.ORG }}.uipath.host/${APP_NAME}"
echo "Checking $APP_URL"
for i in 1 2 3; do
if curl -sf --max-time 10 "$APP_URL" > /dev/null; then
echo "Health check passed on attempt $i"
exit 0
fi
echo "Attempt $i failed, retrying in 10s..."
sleep 10
done
echo "Health check failed after 3 attempts"
exit 1
Comment on lines +89 to +158

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alpha-cli job is a verbatim copy of stable-cli — 5 of 6 steps are identical. Only the "Install CLI" step differs. Any future change to Pack, Publish, Deploy, or Health-check steps must be made in two places, which is an ongoing maintenance hazard.

Refactor using a matrix strategy:

jobs:
  smoke:
    name: ${{ matrix.label }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - label: Stable CLI (npm @latest)
            app_name: cli-smoke-stable
            install_from_gh_packages: false
          - label: Alpha CLI (GH Packages)
            app_name: cli-smoke-alpha
            install_from_gh_packages: true
    env:
      APP_NAME: ${{ matrix.app_name }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - name: Install CLI
        run: |
          if [ "${{ matrix.install_from_gh_packages }}" = "true" ]; then
            echo "//npm.pkg.github.com/:_authToken=${{ secrets.GH_PACKAGES_TOKEN }}" >> ~/.npmrc
            echo "@uipath:registry=https://npm.pkg.github.com" >> ~/.npmrc
            npm i -g @uipath/cli
          else
            npm i -g @uipath/cli@latest
          fi
          uip tools update
      # ... shared Pack / Publish / Deploy / Health-check / Cleanup steps

This also naturally handles the packages: read permission — it can be set at the job level with if: matrix.install_from_gh_packages or simply granted for all matrix legs since the stable leg never hits npm.pkg.github.com.


notify:
name: Slack Alert on Failure
runs-on: ubuntu-latest
needs: [stable-cli, alpha-cli]
if: failure() || contains(needs.*.result, 'cancelled')
permissions: {}
steps:
- name: Build failure message
id: msg
run: |
FAILED_JOBS=""
if [ "${{ needs.stable-cli.result }}" = "failure" ] || [ "${{ needs.stable-cli.result }}" = "cancelled" ]; then
FAILED_JOBS="stable-cli (npm @latest)"
fi
if [ "${{ needs.alpha-cli.result }}" = "failure" ] || [ "${{ needs.alpha-cli.result }}" = "cancelled" ]; then
[ -n "$FAILED_JOBS" ] && FAILED_JOBS="$FAILED_JOBS, "
FAILED_JOBS="${FAILED_JOBS}alpha-cli (GH Packages)"
fi
RUN_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
echo "text=:red_circle: *CLI Smoke Test Failed*\nJobs: ${FAILED_JOBS}\nRun: ${RUN_URL}" >> "$GITHUB_OUTPUT"

- name: Post to Slack
uses: slackapi/slack-github-action@v3

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow or composite action Medium

Unpinned 3rd party Action 'CLI Smoke Test' step
Uses Step
uses 'slackapi/slack-github-action' with ref 'v3', not a pinned commit hash
with:
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two problems here:

1. Secret name mismatch with the PR description

The setup table in the PR description documents SLACK_WEBHOOK_URL (an incoming webhook), but the implementation uses SLACK_BOT_TOKEN (a bot token for the chat.postMessage API method). These are entirely different Slack authentication methods. If the repo only has SLACK_WEBHOOK_URL configured (as the docs say), SLACK_BOT_TOKEN will resolve to an empty string and the step will fail with an authentication error. The PR description's setup table needs to document SLACK_BOT_TOKEN (not SLACK_WEBHOOK_URL).

2. "Gracefully skipped if missing" is not implemented

The PR description says: "optional, gracefully skipped if missing". But there is no if: condition on this step — if SLACK_BOT_TOKEN is absent, the step runs and fails. Add a guard to match the documented behavior:

Suggested change
token: ${{ secrets.SLACK_BOT_TOKEN }}
- name: Post to Slack
if: ${{ secrets.SLACK_BOT_TOKEN != '' }}
uses: slackapi/slack-github-action@v3
with:
method: chat.postMessage
token: ${{ secrets.SLACK_BOT_TOKEN }}

(And update the setup table to list SLACK_BOT_TOKEN, not SLACK_WEBHOOK_URL.)

Comment thread
Raina451 marked this conversation as resolved.
payload: |
channel: "C0AMP09RXH7"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Slack channel ID is hardcoded. Like ORG, TENANT, and FOLDER_KEY (see open thread on line 16), this is internal infrastructure detail committed to the repo. If the channel is archived or the workspace migrates, this silently breaks all failure alerts.

Move it to a repository variable:

Suggested change
channel: "C0AMP09RXH7"
channel: "${{ vars.SMOKE_TEST_SLACK_CHANNEL_ID }}"

Then add SMOKE_TEST_SLACK_CHANNEL_ID to the setup table in the PR description alongside the other required variables.

text: "${{ steps.msg.outputs.text }}"
5 changes: 5 additions & 0 deletions fixtures/smoke-test-app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>CLI Smoke Test</title></head>
<body><h1>cli-smoke-test</h1></body>
</html>
Loading