Skip to content

Commit a2a0ca9

Browse files
authored
Master merge
2 parents 79d45d1 + e164271 commit a2a0ca9

15 files changed

Lines changed: 380 additions & 498 deletions

File tree

‎.coderabbit.yaml‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
inheritance: true
2+
reviews:
3+
review_details: true
4+
request_changes_workflow: true
5+
auto_review:
6+
enabled: true
7+
knowledge_base:
8+
code_guidelines:
9+
filePatterns:
10+
- "browserstack/browserstack-ai-harness:stacks/stack-domain-browserstack-cypress-cli/rules/**/*.md"
11+
- "browserstack/browserstack-ai-harness:stacks/stack-domain-browserstack-cypress-cli/agents/*review*.md"
12+
- "browserstack/browserstack-ai-harness:stacks/stack-domain-browserstack-cypress-cli/skills/*review*/**/*.md"
13+
- "browserstack/browserstack-ai-harness:stacks/stack-domain-browserstack-cypress-cli/knowledge/*.md"
14+
- "browserstack/browserstack-ai-harness:stacks/stack-domain-browserstack-cypress-cli/knowledge/automate/**/*.md"
15+
- "browserstack/browserstack-ai-harness:stacks/stack-domain-browserstack-cypress-cli/knowledge/docs/**/*.md"

‎.github/workflows/Semgrep.yml‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ jobs:
2727

2828
container:
2929
# A Docker image with Semgrep installed. Do not change this.
30-
image: returntocorp/semgrep:1.166.0
30+
# Pinned to a digest for supply-chain integrity (APS-19017 / INF-007).
31+
# returntocorp/semgrep:1.166.0 resolved 2026-09-16.
32+
image: returntocorp/semgrep:1.166.0@sha256:c180f0c93a17b420c0af5006214a29d3c747c5459c732b740191adf657dd0068
33+
3134
# Skip any PR created by dependabot to avoid permission issues:
3235
if: (github.actor != 'dependabot[bot]')
3336

‎.npmrc‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1+
min-release-age=7
12
package-lock=true
23
lockfile-version=1
4+
strict-ssl=true
5+
save-exact=true

‎bin/commands/runs.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ module.exports = function run(args, rawArgs) {
212212
logger.debug("Completed setting the configs");
213213

214214
if(!isBrowserstackInfra) {
215-
if(process.env.BS_TESTOPS_BUILD_COMPLETED) {
215+
if(process.env.BS_TESTOPS_BUILD_COMPLETED === "true") {
216216
setEventListeners(bsConfig);
217217
}
218218

@@ -226,7 +226,7 @@ module.exports = function run(args, rawArgs) {
226226
if(process.env.BROWSERSTACK_TEST_ACCESSIBILITY === 'true') {
227227
setAccessibilityEventListeners(bsConfig);
228228
}
229-
if(process.env.BS_TESTOPS_BUILD_COMPLETED) {
229+
if(process.env.BS_TESTOPS_BUILD_COMPLETED === "true") {
230230
setEventListeners(bsConfig);
231231
}
232232
markBlockEnd('validateConfig');

‎bin/helpers/buildArtifacts.js‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const logger = require('./logger').winstonLogger,
1111
const { default: axios } = require('axios');
1212
const { HttpsProxyAgent = require('https-proxy-agent') } = require('https-proxy-agent');
1313
const FormData = require('form-data');
14-
const decompress = require('decompress');
14+
const AdmZip = require('adm-zip');
1515
const unzipper = require("unzipper");
1616
const { setAxiosProxy } = require('./helper');
1717

@@ -154,10 +154,11 @@ const downloadAndUnzip = async (filePath, fileName, url) => {
154154
const unzipFile = async (filePath, fileName) => {
155155
return new Promise( async (resolve, reject) => {
156156
try {
157-
await decompress(path.join(filePath, fileName), filePath);
157+
const zip = new AdmZip(path.join(filePath, fileName));
158+
await zip.extractAllToAsync(filePath, /* overwrite */ true);
158159
resolve();
159160
} catch (error) {
160-
logger.debug(`Error unzipping with decompress, trying with unzipper. Stacktrace: ${error}.`);
161+
logger.debug(`Error unzipping with adm-zip, trying with unzipper. Stacktrace: ${error}.`);
161162
try {
162163
fs.createReadStream(path.join(filePath, fileName))
163164
.pipe(unzipper.Extract({ path: filePath }))

‎bin/helpers/capabilityHelper.js‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const { readCypressConfigFile } = require('./readCypressConfigUtil');
44

55
const logger = require("./logger").winstonLogger,
66
Constants = require("./constants"),
7-
Utils = require("./utils");
7+
Utils = require("./utils"),
8+
testhubUtils = require("../testhub/utils");
89

910
const caps = (bsConfig, zip) => {
1011
return new Promise(function (resolve, reject) {
@@ -131,6 +132,18 @@ const caps = (bsConfig, zip) => {
131132
obj.run_settings = JSON.stringify(bsConfig.run_settings);
132133
}
133134

135+
// The only route by which a cypress session can name its TestHub build: every session
136+
// this build spawns inherits these caps. Written unconditionally so an empty uuid records
137+
// that build start ran and had nothing to name, which an absent key cannot express.
138+
// "null" is the sentinel a failed build start leaves behind, not a uuid.
139+
const testhubBuildUuid = process.env.BROWSERSTACK_TESTHUB_UUID;
140+
obj.testhubBuildUuid = Utils.isUndefined(testhubBuildUuid) || testhubBuildUuid === "null"
141+
? ""
142+
: testhubBuildUuid;
143+
obj.buildProductMap = testhubUtils.getProductMap(bsConfig);
144+
145+
logger.debug(`TestHub build uuid stamped on caps: ${obj.testhubBuildUuid || "<empty>"}`);
146+
134147
obj.cypress_cli_user_agent = Utils.getUserAgent();
135148

136149
logger.info(`Cypress CLI User Agent: ${obj.cypress_cli_user_agent}`);

‎bin/helpers/reporterHTML.js‎

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const fs = require('fs'),
66
utils = require("./utils"),
77
Constants = require('./constants'),
88
config = require("./config"),
9-
decompress = require('decompress');
9+
AdmZip = require('adm-zip');
1010
const { isTurboScaleSession } = require('../helpers/atsHelper');
1111

1212
const { setAxiosProxy } = require('./helper');
@@ -171,15 +171,14 @@ function getReportResponse(filePath, fileName, reportJsonUrl) {
171171

172172
const unzipFile = async (filePath, fileName) => {
173173
return new Promise( async (resolve, reject) => {
174-
await decompress(path.join(filePath, fileName), filePath)
175-
.then((files) => {
176-
let message = "Unzipped the json and html successfully."
177-
resolve(message);
178-
})
179-
.catch((error) => {
174+
try {
175+
const zip = new AdmZip(path.join(filePath, fileName));
176+
await zip.extractAllToAsync(filePath, /* overwrite */ true);
177+
resolve("Unzipped the json and html successfully.");
178+
} catch (error) {
180179
reject(error);
181180
process.exitCode = Constants.ERROR_EXIT_CODE;
182-
});
181+
}
183182
});
184183
}
185184

‎bin/testhub/testhubHandler.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ class TestHubHandler {
4141
const response = await nodeRequest( "POST", TESTHUB_CONSTANTS.TESTHUB_BUILD_API, data, config);
4242
const launchData = this.extractDataFromResponse(user_config, data, response, config);
4343
} catch (error) {
44-
console.log(error);
44+
logger.debug(`EXCEPTION IN BUILD START EVENT : ${error}`);
45+
testhubUtils.handleErrorForObservability(error.success === false ? error : null);
4546
if (error.success === false) { // non 200 response
46-
testhubUtils.logBuildError(error);
4747
return;
4848
}
4949

‎bin/testhub/utils.js‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ exports.setTestObservabilityVariables = (
8888
};
8989

9090
exports.handleErrorForObservability = (error = null) => {
91+
// Downstream reads isTestObservabilitySession(), not these ids, to decide whether
92+
// observability is live. extractDataFromResponse clears it inline for a 2xx carrying
93+
// success=false; this covers the paths that never get a usable response at all.
94+
process.env.BROWSERSTACK_TEST_OBSERVABILITY = "false";
9195
process.env.BROWSERSTACK_TESTHUB_UUID = "null";
9296
process.env.BROWSERSTACK_TESTHUB_JWT = "null";
9397
process.env.BS_TESTOPS_BUILD_COMPLETED = "false";
@@ -164,7 +168,7 @@ exports.handleErrorForAccessibility = (user_config, error = null) => {
164168
};
165169

166170
exports.logBuildError = (error, product = "") => {
167-
if (error === undefined) {
171+
if (isUndefined(error)) {
168172
logger.error(`${product.toUpperCase()} Build creation failed`);
169173

170174
return;

0 commit comments

Comments
 (0)