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
33 changes: 0 additions & 33 deletions .eslintrc

This file was deleted.

42 changes: 42 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Build

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install
run: npm ci

- name: Lint
run: npm run lint

- name: Test
run: npm test

- name: Package
run: npm run package

- name: Upload VSIX
uses: actions/upload-artifact@v4
with:
name: vsix
path: Packages/*.vsix
if-no-files-found: error
60 changes: 13 additions & 47 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '30 4 * * 2'
Expand All @@ -32,40 +20,18 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
language: [ 'javascript-typescript' ]

steps:
- name: Checkout repository
uses: actions/checkout@v2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
44 changes: 44 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Publishes the extension to the Visual Studio Marketplace when a v* tag is
# pushed. Requires a one-time setup by a maintainer:
# 1. Bump "version" in package.json (the Marketplace rejects a version that
# already exists), commit, then tag: git tag v0.3.0 && git push --tags
# 2. Add a repository secret AZURE_DEVOPS_MARKETPLACE_PAT — a Marketplace
# "Manage" Personal Access Token for the `testingbot` publisher.
#
# NOTE: all-organization PATs are being retired on 2026-12-01. The longer-term
# path is federated Entra/OIDC auth (e.g. the jessehouwing/azdo-marketplace
# action); switch to that before then.
name: Publish

on:
push:
tags: [ 'v*' ]
workflow_dispatch:

permissions:
contents: read

jobs:
publish:
runs-on: ubuntu-latest
environment: marketplace
steps:
- uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Set persist-credentials: false on all checkout steps. actions/checkout@v4 persists the GITHUB_TOKEN in .git/config by default. None of these workflows need git credentials after checkout, and leaving the token persisted expands the attack surface if a later step is compromised.

  • .github/workflows/publish.yml#L26: Add persist-credentials: false — most critical since this workflow handles a Marketplace PAT.
  • .github/workflows/build.yml#L16: Add persist-credentials: false.
  • .github/workflows/codeql-analysis.yml#L27: Add persist-credentials: false.
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 26-26: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 26-26: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

📍 Affects 3 files
  • .github/workflows/publish.yml#L26-L26 (this comment)
  • .github/workflows/build.yml#L16-L16
  • .github/workflows/codeql-analysis.yml#L27-L27
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml at line 26, Configure every
actions/checkout@v4 step with persist-credentials: false: update
.github/workflows/publish.yml at lines 26-26, .github/workflows/build.yml at
lines 16-16, and .github/workflows/codeql-analysis.yml at lines 27-27. No other
workflow changes are required.

with:
persist-credentials: false

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install
run: npm ci

- name: Package
run: npm run package

- name: Publish to the Marketplace
run: npx tfx extension publish --vsix Packages/*.vsix --token "$AZURE_DEVOPS_MARKETPLACE_PAT"
env:
AZURE_DEVOPS_MARKETPLACE_PAT: ${{ secrets.AZURE_DEVOPS_MARKETPLACE_PAT }}
6 changes: 4 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ version in the checked-in `vss-extension.json` / `task.json`.
Tests: `npm test` compiles and runs the mocha suites under `tb-*/tests/` (they
use `azure-pipelines-task-lib`'s `mock-run`/`mock-test`; `MockTestRunner`
downloads the Node20 runtime on first run, so the first `npm test` is slow).
There is no lint wired up yet (the old `.eslintrc` targets the removed
babel-eslint) — planned for Phase 4 (see `MODERNIZATION.md`).
Lint: `npm run lint` runs ESLint (flat config in `eslint.config.mjs`,
typescript-eslint for the `.ts` tasks; the legacy tab scripts are linted
leniently). CI (`.github/workflows/build.yml`) runs lint + tests + a full
package build on every PR targeting `master`.

## Architecture

Expand Down
19 changes: 0 additions & 19 deletions Jenkinsfile

This file was deleted.

11 changes: 8 additions & 3 deletions MODERNIZATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ _Date: 2026-07-17. Applies to repo `vso-testingbot-plugin` (marketplace: `testin
> browser until TestingBot adds such an endpoint; (b) the `vss-web-extension-sdk`
> → `azure-devops-extension-sdk` / React port (large, and the old SDK keeps
> working, so deferred to its own PR).
> - **Phase 4 — PENDING:** CI/CD, lint, publishing.
> - **Phase 4 — MOSTLY DONE (PR #20):** GitHub Actions build workflow (lint +
> tests + package on every PR), ESLint flat config wired up (`npm run lint`),
> CodeQL workflow fixed (v3 actions), dead Jenkinsfile removed, README usage
> quick-start. A tag-triggered publish workflow is included but needs a
> maintainer to add the `AZURE_DEVOPS_MARKETPLACE_PAT` secret (and, before
> 2026-12-01, to move to Entra/OIDC auth).
Comment thread
coderabbitai[bot] marked this conversation as resolved.
>
> Items marked "PENDING" below are the genuinely outstanding work.
>
Expand All @@ -40,7 +45,7 @@ This extension is a 2016-era fork of Sauce Labs' now-unpublished `vso-sauce-onde
2. **Migrate both tasks to the `Node20_1` handler + `azure-pipelines-task-lib` 5.x** — the bare `"Node"` (Node 6) handler is removed from new agents in November 2026; the extension breaks on schedule without this. _(DONE — Phase 1/2.)_
3. **Replace the broken gulp 3 / webpack 1 / babel 6 toolchain** with TypeScript + webpack 5 + npm scripts (per `microsoft/azure-devops-extension-sample`) so a `.vsix` can be built at all. _(DONE — Phase 1 build, Phase 2 TypeScript.)_
4. **Stop bundling the 2019 tunnel jar** (`tb-main/tunnel/2.30.jar`, internally v2.9, vulnerable Jetty 9.4.12) — use `testingbot-tunnel-launcher` (npm, v1.1.18) to download/cache the current tunnel (v4.8) at runtime. _(DONE — Phase 2.)_
5. **Add real CI/CD** — GitHub Actions building the `.vsix` on every PR and publishing to the Marketplace on tag (tfx-cli 0.23.x, Entra/OIDC auth), replacing dead Travis/Jenkins/CodeQL v1 configs. _(PENDING — Phase 4.)_
5. **Add real CI/CD** — GitHub Actions building the `.vsix` on every PR and publishing to the Marketplace on tag (tfx-cli 0.23.x, Entra/OIDC auth), replacing dead Travis/Jenkins/CodeQL v1 configs. _(DONE — Phase 4; the build/CodeQL/lint workflows run, the tag publish workflow just needs the maintainer's Marketplace secret.)_

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the implemented PAT authentication accurately.

The publish workflow currently passes AZURE_DEVOPS_MARKETPLACE_PAT to tfx extension publish in .github/workflows/publish.yml Lines 41-44; Entra/OIDC is a future migration, not the implemented authentication path. Update this entry to say PAT-based publishing is implemented and OIDC remains pending.

Proposed fix
-5. **Add real CI/CD** — GitHub Actions building the `.vsix` on every PR and publishing to the Marketplace on tag (tfx-cli 0.23.x, Entra/OIDC auth), replacing dead Travis/Jenkins/CodeQL v1 configs.
+5. **Add real CI/CD** — GitHub Actions building the `.vsix` on every PR and publishing to the Marketplace on tag (tfx-cli 0.23.x, PAT auth for now; Entra/OIDC migration pending), replacing dead Travis/Jenkins/CodeQL v1 configs.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
5. **Add real CI/CD** — GitHub Actions building the `.vsix` on every PR and publishing to the Marketplace on tag (tfx-cli 0.23.x, Entra/OIDC auth), replacing dead Travis/Jenkins/CodeQL v1 configs. _(DONE — Phase 4; the build/CodeQL/lint workflows run, the tag publish workflow just needs the maintainer's Marketplace secret.)_
5. **Add real CI/CD** — GitHub Actions building the `.vsix` on every PR and publishing to the Marketplace on tag (tfx-cli 0.23.x, PAT auth for now; Entra/OIDC migration pending), replacing dead Travis/Jenkins/CodeQL v1 configs. _(DONE — Phase 4; the build/CodeQL/lint workflows run, the tag publish workflow just needs the maintainer's Marketplace secret.)_
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MODERNIZATION.md` at line 48, Update the Phase 4 CI/CD entry in
MODERNIZATION.md to accurately state that Marketplace publishing currently uses
the AZURE_DEVOPS_MARKETPLACE_PAT with tfx extension publish, while Entra/OIDC
authentication remains a future migration. Preserve the existing
completed-status context.


## 2. Critical bugs & security issues (verified findings)

Expand Down Expand Up @@ -119,7 +124,7 @@ Goal: a results tab with no secrets in the browser, no CDN scripts, and a suppor
| 4.2 GitHub Actions build workflow | **S** | On PR/push: Node 20, `npm ci`, lint, tests, build, `tfx extension create`, upload `.vsix` artifact. This single workflow would have caught the Dependabot gulp4/webpack5 breakage that shipped unnoticed. |
| 4.3 Marketplace publishing on tag | **M** | `jessehouwing/azdo-marketplace@v6` (successor of Azure DevOps Extension Tasks; runs on GitHub Actions): `query-version` (version-source: marketplace, action: Patch) → `publish` with `extension-version` override — no version-commit-back needed. Prefer `auth-type: oidc` (federated Entra) over PATs: all-org PATs are retired **Dec 1, 2026**. Publish a private `-dev` manifest variant to a TestingBot test org before public release (pattern from both the Sauce fork's beta channel and the Microsoft sample). |
| 4.4 Fix CodeQL workflow | **S** | `github/codeql-action/*@v3`, `actions/checkout@v4` (v1 disabled Jan 2023; the repo's only automated check produces no signal today). |
| 4.5 ESLint / formatting refresh | **S** | Replace `babel-eslint` config with `@typescript-eslint` once Phase 2 lands. |
| 4.5 ESLint / formatting refresh | **S** | _(DONE — Phase 4.)_ Replaced the `babel-eslint` `.eslintrc` with an ESLint 9 flat config (`eslint.config.mjs`) using `typescript-eslint`; wired `npm run lint`. |
| 4.6 Docs | **S** | Rewrite README (current build instructions are all broken); add a YAML quick-start (secret variables + script steps) mirroring what Sauce/BrowserStack docs do, for users who cannot install marketplace extensions. |

**Sequencing note:** Phase 1 + steps 2.3/2.4/3.1 are the minimum credible release (fixes the credential leak and the November 2026 handler deadline). Phase 3.2 (SDK port) is the largest single item and can ship in a later minor version.
Expand Down
44 changes: 40 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ into your pipelines: a configuration task that exports your TestingBot credentia
and optionally launches TestingBot Tunnel, a task to stop the tunnel, and a build
results tab.

## Using the tasks in a pipeline

Add a **TestingBot** service connection (Project settings → Service connections →
New → *TestingBot Credentials*) with your key and secret, then reference the tasks:

```yaml
steps:
# Exports TB_KEY / TB_SECRET / SELENIUM_HOST / … and (optionally) starts the tunnel.
- task: TBMain@0
inputs:
connectedServiceName: 'my-testingbot-connection'
tbTunnel: true # optional — needs Java 11+ on the agent

# ... run your Selenium/Appium tests here; they read the exported variables ...

# Only needed when tbTunnel was true. condition: always() ensures the tunnel is
# torn down even if a test step above failed.
- task: TBStopTunnel@0
condition: always()
```

Test results appear on the **TestingBot** tab of the build summary.

## Building the plugin

Requires **Node.js >= 20**.
Expand All @@ -28,9 +51,22 @@ Requires **Node.js >= 20**.

### What `npm run package` does

`clean` → `build` (webpack bundles the results-tab scripts and copies the static
files into `dist/`) → `deps` (installs each task's production `node_modules` into
`dist/`) → `stamp` (writes the version into the built manifest and task
definitions) → `create` (`tfx extension create`).
`clean` → `compile` (`tsc` compiles each task's `index.ts`) → `build` (webpack
bundles the results-tab scripts and copies the static files into `dist/`) →
`deps` (installs each task's production `node_modules` into `dist/`) → `stamp`
(writes the version into the built manifest and task definitions) → `create`
(`tfx extension create`).

To iterate on just the web bundle, run `npm run build`.

## Development

```bash
npm run lint # eslint (flat config, typescript-eslint)
npm test # tsc + mocha task tests
```

CI runs lint, tests and a full package build on every PR targeting `master`
(`.github/workflows/build.yml`). Tagging a commit `v*` publishes to the
Marketplace (`.github/workflows/publish.yml`) — see that file for the required
`AZURE_DEVOPS_MARKETPLACE_PAT` secret and version-bump steps.
69 changes: 69 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import globals from 'globals';

export default tseslint.config(
{
ignores: [
'node_modules/**',
'**/node_modules/**',
'dist/**',
'Packages/**',
// Compiled TypeScript output (emitted next to the sources).
'tb-*/index.js',
'tb-*/index.js.map',
'tb-*/tests/**/*.js',
'**/*.js.map',
// Third-party runtime, not ours to lint.
'lib/**'
]
},

// TypeScript task sources + their tests.
{
files: ['tb-*/**/*.ts'],
extends: [js.configs.recommended, ...tseslint.configs.recommended],
languageOptions: {
globals: { ...globals.node, ...globals.mocha }
},
rules: {
// azure-pipelines-task-lib and testingbot-tunnel-launcher use `export =`,
// for which `import x = require(...)` is the idiomatic TypeScript form.
'@typescript-eslint/no-require-imports': 'off'
}
},

// Node build scripts.
{
files: ['scripts/**/*.js', 'webpack.config.js'],
extends: [js.configs.recommended],
languageOptions: {
globals: globals.node,
sourceType: 'commonjs'
}
},

// Legacy browser tab scripts (slated for the SDK rewrite). Lint for real
// errors only; the vendored MD5 implementation trips a lot of style rules.
{
files: ['tb-build-info/scripts/**/*.js'],
extends: [js.configs.recommended],
languageOptions: {
sourceType: 'commonjs',
globals: {
...globals.browser,
VSS: 'readonly',
$: 'readonly',
jQuery: 'readonly',
Buffer: 'readonly'
}
},
rules: {
'no-unused-vars': 'off',
'no-redeclare': 'off',
'no-inner-declarations': 'off',
'no-empty': 'off',
'no-func-assign': 'off'
}
}
);
Loading
Loading