From 3e710d1229f5057161511a939e7d635e2838bdec Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 25 Feb 2025 14:26:29 -0500 Subject: [PATCH 01/17] adding initial client support --- .github/workflows/stageTestAction.yml | 3 +- example.env | 6 + package.json | 2 + readme.md | 20 + tests/helpers/containers.tsx | 128 +++++++ tests/helpers/loginHelpers.tsx | 3 +- tests/helpers/rhsmClient.tsx | 75 ++++ yarn.lock | 524 ++++++++++++++++++++------ 8 files changed, 651 insertions(+), 110 deletions(-) create mode 100644 tests/helpers/containers.tsx create mode 100644 tests/helpers/rhsmClient.tsx diff --git a/.github/workflows/stageTestAction.yml b/.github/workflows/stageTestAction.yml index 1e3fd7a..f5872d4 100644 --- a/.github/workflows/stageTestAction.yml +++ b/.github/workflows/stageTestAction.yml @@ -47,7 +47,8 @@ jobs: echo "PROXY=$PROXY" >> .env echo "TOKEN=apple" >> .env echo "CI=true" >> .env - + echo "ORG_ID_1=$STAGE_ORG_ID" >> .env + echo "ACTIVATION_KEY_1=$STAGE_ACTIVATION_KEY" >> .env - name: Set up Node.js uses: actions/setup-node@v2 with: diff --git a/example.env b/example.env index c24fb43..dea756b 100644 --- a/example.env +++ b/example.env @@ -3,7 +3,13 @@ USER1USERNAME="contentPlaywrightUserAdmin" # Required USER1PASSWORD="" # Required (Ask Andrew if needed) +ORG_ID_1="1234" #org id to register for registration tests +ACTIVATION_KEY_1="MyKey" #activation Key used for testing + +PROD="" BASE_URL="https://stage.foo.redhat.com:1337" # Required PROXY="https://something.foo.redhat.com:5432" # Required in CI only or if locally running against stage CI="" # This is set to true for CI jobs, if checking for CI do !!process.env.CI TOKEN="" # This is handled programmatically. + +#DOCKER_SOCKET="/tmp/podman.sock" diff --git a/package.json b/package.json index 25cdbee..c05868d 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "dayjs": "^1.11.13" }, "dependencies": { + "@types/dockerode": "^3.3.34", + "dockerode": "^4.0.4", "dotenv": "^16.4.7", "github-actions-ctrf": "^0.0.58", "playwright-ctrf-json-reporter": "^0.0.18" diff --git a/readme.md b/readme.md index f36b1b1..b0d15f4 100644 --- a/readme.md +++ b/readme.md @@ -14,6 +14,26 @@ This stores your local credentials yarn get-tests +# Setup container api for testing with clients + +## Podman + +As your user, run podman to serve the api: +``` +podman system service -t 0 /tmp/podman.sock +``` + +Uncomment the DOCKER_SOCKET option in the .env file: +``` +DOCKER_SOCKET="/tmp/podman.sock" +``` + +## Docker + +* ensure the docker service is running +* ensure your user is part of the 'docker' user group + + # Option 1 Run local: For local testing, make sure your front-end/backend servers are running and accessible, then: diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx new file mode 100644 index 0000000..1f88ac9 --- /dev/null +++ b/tests/helpers/containers.tsx @@ -0,0 +1,128 @@ +import Dockerode, { Container } from "dockerode"; +import { PassThrough } from "stream"; +import { finished } from "stream/promises"; + +var Docker = require("dockerode"); + +const util = require("util"); +const exec = util.promisify(require("child_process").exec); + +const dockerHost = () => { + return process.env.DOCKER_SOCKET!; +}; + +const docker = (): Dockerode => { + return new Docker({ socketPath: dockerHost() }); +}; + +export const startContainer = async ( + containerName: string, + imageName: string +) => { + console.log("starting container " + containerName); + const container = await docker().createContainer({ + Image: imageName, + name: containerName, + }); + return container?.start(); +}; + +/* + * starts a container and kills one if it already exists with the same name + */ +export const startNewContainer = async ( + containerName: string, + imageName: string +) => { + await killContainer(containerName); + return await startContainer(containerName, imageName); + //await waitForContainer(containerName) +}; + +async function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +const waitForContainer = async (name: string): Promise => { + var container = await getContainer(name); + var waited = 10; + while (container == undefined && waited > 0) { + waited -= 1; + await sleep(1000); + container = await getContainer(name); + } + return container; +}; + +const getContainerInfo = async (name: string) => { + const containers = await docker().listContainers({ all: true }); + + for (var contInfo of containers) { + if (contInfo.Names.includes("/" + name)) { + return contInfo; + } + } + return undefined; +}; + +const getContainer = async (name: string): Promise => { + const cInfo = await getContainerInfo(name); + if (cInfo !== undefined) { + return docker().getContainer(cInfo.Id); + } +}; + +export const killContainer = async (containerName: string) => { + const info = await getContainerInfo(containerName); + const c = await getContainer(containerName); + if (info?.State == "running") { + await c?.kill(); + } + return c?.remove(); +}; + +interface ExecReturn { + stdout?: string; + stderr?: string; + exitCode?: number | null; +} + +// Runs a non-interactive command and returns stdout, stderr, and the exit code +export const runCommand = async ( + containerName: string, + command: string[] +): Promise => { + console.log("Running " + command + " on " + containerName); + const c = await getContainer(containerName); + const exec = await c?.exec({ + Cmd: command, + AttachStdout: true, + AttachStderr: true, + }); + if (exec == undefined) { + return undefined; + } + + const execStream = await exec?.start({}); + if (execStream == undefined) { + return undefined; + } + + const stdoutStream = new PassThrough(); + const stderrStream = new PassThrough(); + + docker().modem.demuxStream(execStream, stdoutStream, stderrStream); + + execStream.resume(); + await finished(execStream); + + const stderr = stderrStream.read() as Buffer | undefined; + const stdout = stdoutStream.read() as Buffer | undefined; + const execInfo = await exec.inspect(); + + return { + exitCode: execInfo.ExitCode, + stderr: stderr?.toString(), + stdout: stdout?.toString(), + }; +}; diff --git a/tests/helpers/loginHelpers.tsx b/tests/helpers/loginHelpers.tsx index 8f11ce7..403401e 100644 --- a/tests/helpers/loginHelpers.tsx +++ b/tests/helpers/loginHelpers.tsx @@ -84,7 +84,8 @@ export const throwIfMissingEnvVariables = () => { "USER1USERNAME", "USER1PASSWORD", "BASE_URL", - "PROXY", + "ORG_ID_1", + "ACTIVATION_KEY_1", ]; if (!process.env.PROD) ManditoryEnvVariables.push("PROXY"); diff --git a/tests/helpers/rhsmClient.tsx b/tests/helpers/rhsmClient.tsx new file mode 100644 index 0000000..d742643 --- /dev/null +++ b/tests/helpers/rhsmClient.tsx @@ -0,0 +1,75 @@ +import { URL } from "url"; +import { killContainer, runCommand, startNewContainer } from "./containers"; + +export type OSVersion = "rhel9" | "rhel8"; + +const RemoteImages = { + rhel9: "quay.io/jlsherri/client-rhel9", + rhel8: "localhost/client-rhel9", +}; + +export class RHSMClient { + name: string; + constructor(name: string) { + this.name = name; + } + + async Boot(version: OSVersion) { + return startNewContainer(this.name, RemoteImages[version]); + } + + async ConfigureForStage() { + return runCommand(this.name, stageConfigureCommand()); + } + + async Register(activationKey?: string, orgId?: string) { + if (!process.env.PROD) { + await this.ConfigureForStage(); + } + + if (activationKey == undefined) { + activationKey = process.env.ACTIVATION_KEY_1 || "COULD_NOT_FIND_KEY"; + } + if (activationKey == undefined) { + orgId = process.env.ORG_ID_1 || "COULD_NOT_FIND_ORG_ID"; + } + + return runCommand(this.name, [ + "subscription-manager", + "register", + "--activationkey", + activationKey, + "--org=" + orgId, + "--name", + this.name, + ]); + } + + async Unregister() { + return runCommand(this.name, ["subscription-manager", "unregister"]); + } + + async Destroy() { + const cmd = await this.Unregister(); + console.log(cmd?.stdout); + console.log(cmd?.stderr); + return killContainer(this.name); + } +} + +const stageConfigureCommand = (): string[] => { + var command = [ + "subscription-manager", + "config", + "--server.hostname=subscription.rhsm.stage.redhat.com", + "--server.port=443", + "--server.prefix=/subscription", + "--server.insecure=0", + ]; + if (process.env.PROXY !== undefined) { + const url = new URL(process.env.PROXY); + command.push("--server.proxy_hostname=" + url.hostname); + command.push("--server.proxy_port=" + url.port); + } + return command; +}; diff --git a/yarn.lock b/yarn.lock index 72a55ce..4f77519 100644 --- a/yarn.lock +++ b/yarn.lock @@ -54,6 +54,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== +"@balena/dockerignore@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" + integrity sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q== + "@commander-js/extra-typings@^12.1.0": version "12.1.0" resolved "https://registry.yarnpkg.com/@commander-js/extra-typings/-/extra-typings-12.1.0.tgz#5441bae756d326d34f1b9dceb0d78dbf5bc05d81" @@ -116,6 +121,24 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== +"@grpc/grpc-js@^1.11.1": + version "1.13.0" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.13.0.tgz#69c229eacb77f3468afa9d375c23dc9b694d1af9" + integrity sha512-pMuxInZjUnUkgMT2QLZclRqwk2ykJbIU05aZgPgJYXEpN9+2I7z7aNwcjWZSycRPl232FfhPszyBFJyOxTHNog== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.7.13": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -128,15 +151,20 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + "@octokit/auth-token@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-4.0.0.tgz#40d203ea827b9f17f42a29c6afb93b7745ef80c7" integrity sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA== "@octokit/auth-token@^5.0.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-5.1.1.tgz#3bbfe905111332a17f72d80bd0b51a3e2fa2cf07" - integrity sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA== + version "5.1.2" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-5.1.2.tgz#68a486714d7a7fd1df56cb9bc89a860a0de866de" + integrity sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw== "@octokit/core@^5.0.1": version "5.2.0" @@ -151,51 +179,51 @@ before-after-hook "^2.2.0" universal-user-agent "^6.0.0" -"@octokit/core@^6.1.3": - version "6.1.3" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-6.1.3.tgz#280d3bb66c702297baac0a202219dd66611286e4" - integrity sha512-z+j7DixNnfpdToYsOutStDgeRzJSMnbj8T1C/oQjB6Aa+kRfNjs/Fn7W6c8bmlt6mfy3FkgeKBRnDjxQow5dow== +"@octokit/core@^6.1.4": + version "6.1.4" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-6.1.4.tgz#f5ccf911cc95b1ce9daf6de425d1664392f867db" + integrity sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg== dependencies: "@octokit/auth-token" "^5.0.0" "@octokit/graphql" "^8.1.2" - "@octokit/request" "^9.1.4" - "@octokit/request-error" "^6.1.6" + "@octokit/request" "^9.2.1" + "@octokit/request-error" "^6.1.7" "@octokit/types" "^13.6.2" before-after-hook "^3.0.2" universal-user-agent "^7.0.0" -"@octokit/endpoint@^10.0.0": - version "10.1.2" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-10.1.2.tgz#d38e727e2a64287114fdaa1eb9cd7c81c09460df" - integrity sha512-XybpFv9Ms4hX5OCHMZqyODYqGTZ3H6K6Vva+M9LR7ib/xr1y1ZnlChYv9H680y77Vd/i/k+thXApeRASBQkzhA== +"@octokit/endpoint@^10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-10.1.3.tgz#bfe8ff2ec213eb4216065e77654bfbba0fc6d4de" + integrity sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA== dependencies: "@octokit/types" "^13.6.2" universal-user-agent "^7.0.2" -"@octokit/endpoint@^9.0.1": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.5.tgz#e6c0ee684e307614c02fc6ac12274c50da465c44" - integrity sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw== +"@octokit/endpoint@^9.0.6": + version "9.0.6" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.6.tgz#114d912108fe692d8b139cfe7fc0846dfd11b6c0" + integrity sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw== dependencies: "@octokit/types" "^13.1.0" universal-user-agent "^6.0.0" "@octokit/graphql@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-7.1.0.tgz#9bc1c5de92f026648131f04101cab949eeffe4e0" - integrity sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ== + version "7.1.1" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-7.1.1.tgz#79d9f3d0c96a8fd13d64186fe5c33606d48b79cc" + integrity sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g== dependencies: - "@octokit/request" "^8.3.0" + "@octokit/request" "^8.4.1" "@octokit/types" "^13.0.0" universal-user-agent "^6.0.0" "@octokit/graphql@^8.1.2": - version "8.1.2" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-8.1.2.tgz#98b9072b22e0471b782d52ed0da08e2b2de52b17" - integrity sha512-bdlj/CJVjpaz06NBpfHhp4kGJaRZfz7AzC+6EwUImRtrwIw8dIgJ63Xg0OzV9pRn3rIzrt5c2sa++BL0JJ8GLw== + version "8.2.1" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-8.2.1.tgz#0cb83600e6b4009805acc1c56ae8e07e6c991b78" + integrity sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw== dependencies: - "@octokit/request" "^9.1.4" - "@octokit/types" "^13.6.2" + "@octokit/request" "^9.2.2" + "@octokit/types" "^13.8.0" universal-user-agent "^7.0.0" "@octokit/openapi-types@^20.0.0": @@ -208,17 +236,17 @@ resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-23.0.1.tgz#3721646ecd36b596ddb12650e0e89d3ebb2dd50e" integrity sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g== -"@octokit/plugin-paginate-rest@^11.4.0": - version "11.4.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.0.tgz#a9c3347113d793e48a014f0aa549eada00de7c9a" - integrity sha512-ttpGck5AYWkwMkMazNCZMqxKqIq1fJBNxBfsFwwfyYKTf914jKkLF0POMS3YkPBwp5g1c2Y4L79gDz01GhSr1g== +"@octokit/plugin-paginate-rest@^11.4.2": + version "11.4.3" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.3.tgz#b5030bba2e0ecff8e6ff7501074c1b209af78ff8" + integrity sha512-tBXaAbXkqVJlRoA/zQVe9mUdb8rScmivqtpv3ovsC5xhje/a+NOCivs7eUhWBwCApJVsR4G5HMeaLbq7PxqZGA== dependencies: "@octokit/types" "^13.7.0" "@octokit/plugin-paginate-rest@^9.0.0": - version "9.2.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz#2e2a2f0f52c9a4b1da1a3aa17dabe3c459b9e401" - integrity sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw== + version "9.2.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz#c516bc498736bcdaa9095b9a1d10d9d0501ae831" + integrity sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ== dependencies: "@octokit/types" "^12.6.0" @@ -235,56 +263,56 @@ "@octokit/types" "^12.6.0" "@octokit/plugin-rest-endpoint-methods@^13.3.0": - version "13.3.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.0.tgz#ee18b9d6364bbae1d86e960d5576b555b41d2079" - integrity sha512-LUm44shlmkp/6VC+qQgHl3W5vzUP99ZM54zH6BuqkJK4DqfFLhegANd+fM4YRLapTvPm4049iG7F3haANKMYvQ== + version "13.3.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.1.tgz#1915976b689662f14d033a16e7d9307c22842234" + integrity sha512-o8uOBdsyR+WR8MK9Cco8dCgvG13H1RlM1nWnK/W7TEACQBFux/vPREgKucxUfuDQ5yi1T3hGf4C5ZmZXAERgwQ== dependencies: - "@octokit/types" "^13.7.0" + "@octokit/types" "^13.8.0" -"@octokit/request-error@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.0.tgz#ee4138538d08c81a60be3f320cd71063064a3b30" - integrity sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q== +"@octokit/request-error@^5.1.0", "@octokit/request-error@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.1.tgz#b9218f9c1166e68bb4d0c89b638edc62c9334805" + integrity sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g== dependencies: "@octokit/types" "^13.1.0" deprecation "^2.0.0" once "^1.4.0" -"@octokit/request-error@^6.0.1", "@octokit/request-error@^6.1.6": - version "6.1.6" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.6.tgz#5f42c7894e7c3ab47c63aa3241f78cee8a826644" - integrity sha512-pqnVKYo/at0NuOjinrgcQYpEbv4snvP3bKMRqHaD9kIsk9u1LCpb2smHZi8/qJfgeNqLo5hNW4Z7FezNdEo0xg== +"@octokit/request-error@^6.1.7": + version "6.1.7" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.7.tgz#44fc598f5cdf4593e0e58b5155fe2e77230ff6da" + integrity sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g== dependencies: "@octokit/types" "^13.6.2" -"@octokit/request@^8.3.0", "@octokit/request@^8.3.1": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.0.tgz#7f4b7b1daa3d1f48c0977ad8fffa2c18adef8974" - integrity sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw== +"@octokit/request@^8.3.1", "@octokit/request@^8.4.1": + version "8.4.1" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.4.1.tgz#715a015ccf993087977ea4365c44791fc4572486" + integrity sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw== dependencies: - "@octokit/endpoint" "^9.0.1" - "@octokit/request-error" "^5.1.0" + "@octokit/endpoint" "^9.0.6" + "@octokit/request-error" "^5.1.1" "@octokit/types" "^13.1.0" universal-user-agent "^6.0.0" -"@octokit/request@^9.1.4": - version "9.1.4" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.1.4.tgz#c1e90bd57c3113253d27337c92609b8fed54d13b" - integrity sha512-tMbOwGm6wDII6vygP3wUVqFTw3Aoo0FnVQyhihh8vVq12uO3P+vQZeo2CKMpWtPSogpACD0yyZAlVlQnjW71DA== +"@octokit/request@^9.2.1", "@octokit/request@^9.2.2": + version "9.2.2" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.2.2.tgz#754452ec4692d7fdc32438a14e028eba0e6b2c09" + integrity sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg== dependencies: - "@octokit/endpoint" "^10.0.0" - "@octokit/request-error" "^6.0.1" + "@octokit/endpoint" "^10.1.3" + "@octokit/request-error" "^6.1.7" "@octokit/types" "^13.6.2" fast-content-type-parse "^2.0.0" universal-user-agent "^7.0.2" "@octokit/rest@^21.0.2": - version "21.1.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-21.1.0.tgz#adbd3eca32a686e3d24e7840a58270e030267a1f" - integrity sha512-93iLxcKDJboUpmnUyeJ6cRIi7z7cqTZT1K7kRK4LobGxwTwpsa+2tQQbRQNGy7IFDEAmrtkf4F4wBj3D5rVlJQ== + version "21.1.1" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-21.1.1.tgz#7a70455ca451b1d253e5b706f35178ceefb74de2" + integrity sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg== dependencies: - "@octokit/core" "^6.1.3" - "@octokit/plugin-paginate-rest" "^11.4.0" + "@octokit/core" "^6.1.4" + "@octokit/plugin-paginate-rest" "^11.4.2" "@octokit/plugin-request-log" "^5.3.1" "@octokit/plugin-rest-endpoint-methods" "^13.3.0" @@ -295,19 +323,72 @@ dependencies: "@octokit/openapi-types" "^20.0.0" -"@octokit/types@^13.0.0", "@octokit/types@^13.1.0", "@octokit/types@^13.6.2", "@octokit/types@^13.7.0": - version "13.7.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.7.0.tgz#22d0e26a8c9f53599bfb907213d8ccde547f36aa" - integrity sha512-BXfRP+3P3IN6fd4uF3SniaHKOO4UXWBfkdR3vA8mIvaoO/wLjGN5qivUtW0QRitBHHMcfC41SLhNVYIZZE+wkA== +"@octokit/types@^13.0.0", "@octokit/types@^13.1.0", "@octokit/types@^13.6.2", "@octokit/types@^13.7.0", "@octokit/types@^13.8.0": + version "13.8.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.8.0.tgz#3815885e5abd16ed9ffeea3dced31d37ce3f8a0a" + integrity sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A== dependencies: "@octokit/openapi-types" "^23.0.1" "@playwright/test@^1.49.1": - version "1.49.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.1.tgz#55fa360658b3187bfb6371e2f8a64f50ef80c827" - integrity sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g== + version "1.51.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.51.0.tgz#8d5c8400b465a0bfdbcf993e390ceecb903ea6d2" + integrity sha512-dJ0dMbZeHhI+wb77+ljx/FeC8VBP6j/rj9OAojO08JI80wTZy6vRk9KvHKiDCUh4iMpEiseMgqRBIeW+eKX6RA== + dependencies: + playwright "1.51.0" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== dependencies: - playwright "1.49.1" + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== "@sec-ant/readable-stream@^0.4.1": version "0.4.1" @@ -326,20 +407,44 @@ dependencies: "@types/node" "*" -"@types/node@*": - version "22.10.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.6.tgz#5c6795e71635876039f853cbccd59f523d9e4239" - integrity sha512-qNiuwC4ZDAUNcY47xgaSuS92cjf8JbSUoaKS77bmLG1rU7MlATVSiw/IlrjtIyyskXBZ8KkNfjK/P5na7rgXbQ== +"@types/docker-modem@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/docker-modem/-/docker-modem-3.0.6.tgz#1f9262fcf85425b158ca725699a03eb23cddbf87" + integrity sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg== dependencies: - undici-types "~6.20.0" + "@types/node" "*" + "@types/ssh2" "*" + +"@types/dockerode@^3.3.34": + version "3.3.35" + resolved "https://registry.yarnpkg.com/@types/dockerode/-/dockerode-3.3.35.tgz#d78c844a246f8717e3bcf2cc134a976bfa630b10" + integrity sha512-P+DCMASlsH+QaKkDpekKrP5pLls767PPs+/LrlVbKnEnY5tMpEUa2C6U4gRsdFZengOqxdCIqy16R22Q3pLB6Q== + dependencies: + "@types/docker-modem" "*" + "@types/node" "*" + "@types/ssh2" "*" -"@types/node@^22.9.0": - version "22.13.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.0.tgz#d376dd9a0ee2f9382d86c2d5d7beb4d198b4ea8c" - integrity sha512-ClIbNe36lawluuvq3+YYhnIN2CELi+6q8NpnM7PYp4hBn/TatfboPgVSm2rwKRfnV2M+Ty9GWDFI64KEe+kysA== +"@types/node@*", "@types/node@>=13.7.0", "@types/node@^22.9.0": + version "22.13.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.10.tgz#df9ea358c5ed991266becc3109dc2dc9125d77e4" + integrity sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw== dependencies: undici-types "~6.20.0" +"@types/node@^18.11.18": + version "18.19.80" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.80.tgz#6d6008e8920dddcd23f9dd33da24684ef57d487c" + integrity sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ== + dependencies: + undici-types "~5.26.4" + +"@types/ssh2@*": + version "1.15.4" + resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.15.4.tgz#2347d2ff079e205b077c02407d822803bfd23c45" + integrity sha512-9JTQgVBWSgq6mAen6PVnrAmty1lqgCMvpfN+1Ck5WRUsyMYPa6qd50/vMJ0y1zkGpOEgLzm8m8Dx/Y5vRouLaA== + dependencies: + "@types/node" "^18.11.18" + acorn@^8.14.0: version "8.14.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" @@ -400,6 +505,13 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +asn1@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + async-retry@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" @@ -430,9 +542,9 @@ axios-retry@^4.5.0: is-retry-allowed "^2.2.0" axios@^1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.2.tgz#fabe06e241dfe83071d4edfbcaa7b1c3a40f7979" - integrity sha512-ls4GYBm5aig9vWx8AWDSGLpnpDQRtWAfrjU+EuytuODrFBkqesN2RkOQCBzrA1RQNHw1SmRMSDDDSwzNAYQ6Rg== + version "1.8.3" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.3.tgz#9ebccd71c98651d547162a018a1a95a4b4ed4de8" + integrity sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -448,6 +560,13 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bcrypt-pbkdf@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + before-after-hook@^2.2.0: version "2.2.3" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" @@ -463,6 +582,15 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + bluebird@3.5.5: version "3.5.5" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" @@ -487,6 +615,14 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -495,6 +631,11 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +buildcheck@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.6.tgz#89aa6e417cfd1e2196e3f8fe915eb709d2fe4238" + integrity sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A== + c12@^1.11.2: version "1.11.2" resolved "https://registry.yarnpkg.com/c12/-/c12-1.11.2.tgz#f8a1e30c10f4b273894a1bcb6944f76c15b56717" @@ -549,6 +690,11 @@ chokidar@^3.6.0: optionalDependencies: fsevents "~2.3.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + chownr@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" @@ -609,6 +755,14 @@ consola@^3.2.3, consola@^3.4.0: resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.0.tgz#4cfc9348fd85ed16a17940b3032765e31061ab88" integrity sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA== +cpu-features@~0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.10.tgz#9aae536db2710c7254d7ed67cb3cbc7d29ad79c5" + integrity sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA== + dependencies: + buildcheck "~0.0.6" + nan "^2.19.0" + cross-spawn@^6.0.0: version "6.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57" @@ -620,7 +774,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.3: +cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -648,7 +802,7 @@ dayjs@^1.11.13: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== -debug@4, debug@^4.3.7: +debug@4, debug@^4.1.1, debug@^4.3.7: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== @@ -682,6 +836,29 @@ destr@^2.0.3: resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.3.tgz#7f9e97cb3d16dbdca7be52aca1644ce402cfe449" integrity sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ== +docker-modem@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-5.0.6.tgz#cbe9d86a1fe66d7a072ac7fb99a9fc390a3e8b9a" + integrity sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ== + dependencies: + debug "^4.1.1" + readable-stream "^3.5.0" + split-ca "^1.0.1" + ssh2 "^1.15.0" + +dockerode@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-4.0.4.tgz#3db42ce77241cbe5f20eac44afa933dcff59a268" + integrity sha512-6GYP/EdzEY50HaOxTVTJ2p+mB5xDHTMJhS+UoGrVyS6VC+iQRh7kZ4FRpUYq6nziby7hPqWhOrFFUFTMUZJJ5w== + dependencies: + "@balena/dockerignore" "^1.0.2" + "@grpc/grpc-js" "^1.11.1" + "@grpc/proto-loader" "^0.7.13" + docker-modem "^5.0.6" + protobufjs "^7.3.2" + tar-fs "~2.0.1" + uuid "^10.0.0" + dotenv@^16.0.3, dotenv@^16.4.5, dotenv@^16.4.7: version "16.4.7" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" @@ -711,7 +888,7 @@ emoji-regex@^9.2.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -826,11 +1003,11 @@ follow-redirects@^1.15.6: integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== foreground-child@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" - integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== dependencies: - cross-spawn "^7.0.0" + cross-spawn "^7.0.6" signal-exit "^4.0.1" form-data@^4.0.0: @@ -843,6 +1020,11 @@ form-data@^4.0.0: es-set-tostringtag "^2.1.0" mime-types "^2.1.12" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-minipass@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" @@ -1018,7 +1200,7 @@ human-signals@^8.0.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-8.0.0.tgz#2d3d63481c7c2319f0373428b01ffe30da6df852" integrity sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA== -ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -1028,6 +1210,11 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -1093,9 +1280,9 @@ istanbul-lib-coverage@^3.2.2: integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== jackspeak@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.0.2.tgz#11f9468a3730c6ff6f56823a820d7e3be9bef015" - integrity sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw== + version "4.1.0" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.1.0.tgz#c489c079f2b636dc4cbe9b0312a13ff1282e561b" + integrity sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw== dependencies: "@isaacs/cliui" "^8.0.2" @@ -1124,11 +1311,21 @@ lil-http-terminator@^1.2.3: resolved "https://registry.yarnpkg.com/lil-http-terminator/-/lil-http-terminator-1.2.3.tgz#594ef0f3c2b2f7d43a8f2989b2b3de611bf507eb" integrity sha512-vQcHSwAFq/kTR2cG6peOVS7SjgksGgSPeH0G2lkw+buue33thE/FCHdn10wJXXshc5RswFy0Iaz48qA2Busw5Q== +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +long@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.1.tgz#9d4222d3213f38a5ec809674834e0f0ab21abe96" + integrity sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng== + lru-cache@^11.0.0: version "11.0.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.2.tgz#fbd8e7cf8211f5e7e5d91905c415a3f55755ca39" @@ -1188,6 +1385,11 @@ minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -1213,6 +1415,11 @@ ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +nan@^2.19.0, nan@^2.20.0: + version "2.22.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.2.tgz#6b504fd029fb8f38c0990e52ad5c26772fdacfbb" + integrity sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ== + nanoid@^3.3.8: version "3.3.9" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.9.tgz#e0097d8e026b3343ff053e9ccd407360a03f503a" @@ -1422,22 +1629,22 @@ pkg-types@^1.2.0, pkg-types@^1.3.0, pkg-types@^1.3.1: mlly "^1.7.4" pathe "^2.0.1" -playwright-core@1.49.1: - version "1.49.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.49.1.tgz#32c62f046e950f586ff9e35ed490a424f2248015" - integrity sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg== +playwright-core@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.51.0.tgz#bb23ea6bb6298242d088ae5e966ffcf8dc9827e8" + integrity sha512-x47yPE3Zwhlil7wlNU/iktF7t2r/URR3VLbH6EknJd/04Qc/PSJ0EY3CMXipmglLG+zyRxW6HNo2EGbKLHPWMg== playwright-ctrf-json-reporter@^0.0.18: version "0.0.18" resolved "https://registry.yarnpkg.com/playwright-ctrf-json-reporter/-/playwright-ctrf-json-reporter-0.0.18.tgz#74b0d6cd53e3860148070db8cbecb789cac766e4" integrity sha512-AjFNpIMKI8zeyaktA2LBphYzy3ffiBjXobBXxEfrVUDov/Z8v5+y9FI0m3cBCr8yauk2brN+Er225vHsZDIu0g== -playwright@1.49.1: - version "1.49.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.49.1.tgz#830266dbca3008022afa7b4783565db9944ded7c" - integrity sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA== +playwright@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.51.0.tgz#9ba154497ba62bc6dc199c58ee19295eb35a4707" + integrity sha512-442pTfGM0xxfCYxuBa/Pu6B2OqxqqaYq39JS8QDMGThUvIOCd6s0ANDog3uwA0cHavVlnTQzGCN7Id2YekDSXA== dependencies: - playwright-core "1.49.1" + playwright-core "1.51.0" optionalDependencies: fsevents "2.3.2" @@ -1465,6 +1672,24 @@ process-warning@^4.0.0: resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-4.0.1.tgz#5c1db66007c67c756e4e09eb170cdece15da32fb" integrity sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q== +protobufjs@^7.2.5, protobufjs@^7.3.2: + version "7.4.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.4.0.tgz#7efe324ce9b3b61c82aae5de810d287bc08a248a" + integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -1496,6 +1721,15 @@ rc9@^2.1.2: defu "^6.1.4" destr "^2.0.3" +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -1518,11 +1752,21 @@ retry@0.13.1: resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-stable-stringify@^2.3.1: version "2.5.0" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== +safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + semver@^5.5.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" @@ -1582,11 +1826,27 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +split-ca@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" + integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== + split2@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== +ssh2@^1.15.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.16.0.tgz#79221d40cbf4d03d07fe881149de0a9de928c9f0" + integrity sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg== + dependencies: + asn1 "^0.2.6" + bcrypt-pbkdf "^1.0.2" + optionalDependencies: + cpu-features "~0.0.10" + nan "^2.20.0" + stack-utils@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -1621,6 +1881,13 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -1659,6 +1926,27 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +tar-fs@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" + integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.0.0" + +tar-stream@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + tar@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" @@ -1712,10 +2000,15 @@ tunnel@^0.0.6: resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== +tweetnacl@^0.14.3: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + typescript@^5.4.5: - version "5.7.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e" - integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw== + version "5.8.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4" + integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ== ufo@^1.5.4: version "1.5.4" @@ -1727,15 +2020,20 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + undici-types@~6.20.0: version "6.20.0" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== undici@^5.25.4, undici@^5.28.4: - version "5.28.4" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" - integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== + version "5.28.5" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.5.tgz#b2b94b6bf8f1d919bc5a6f31f2c01deb02e54d4b" + integrity sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA== dependencies: "@fastify/busboy" "^2.0.0" @@ -1754,6 +2052,16 @@ universal-user-agent@^7.0.0, universal-user-agent@^7.0.2: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-7.0.2.tgz#52e7d0e9b3dc4df06cc33cb2b9fd79041a54827e" integrity sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q== +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +uuid@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" From 35b53805640944ad051b6f62980546a104f73aa9 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 25 Feb 2025 15:34:57 -0500 Subject: [PATCH 02/17] add docker sock --- .github/workflows/stageTestAction.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/stageTestAction.yml b/.github/workflows/stageTestAction.yml index f5872d4..43ff6db 100644 --- a/.github/workflows/stageTestAction.yml +++ b/.github/workflows/stageTestAction.yml @@ -49,6 +49,7 @@ jobs: echo "CI=true" >> .env echo "ORG_ID_1=$STAGE_ORG_ID" >> .env echo "ACTIVATION_KEY_1=$STAGE_ACTIVATION_KEY" >> .env + echo "DOCKER_SOCKET=/var/run/docker.sock" >> .env - name: Set up Node.js uses: actions/setup-node@v2 with: From 30581c6783cae26388e23ad502bdbebd75e05ba2 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 25 Feb 2025 15:59:18 -0500 Subject: [PATCH 03/17] start docker --- buildspec.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/buildspec.yml b/buildspec.yml index 86b0766..e0d2ad6 100644 --- a/buildspec.yml +++ b/buildspec.yml @@ -4,6 +4,8 @@ phases: install: commands: - echo Entered the install phase... + - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 & + - timeout 15 sh -c "until docker info; do echo .; sleep 1; done" finally: - echo This always runs even if the update or install command fails pre_build: From 36930ab30535cbdfa6084985d49b9f9126a2e4b5 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 25 Feb 2025 16:13:47 -0500 Subject: [PATCH 04/17] pull containers on startup --- buildspec.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/buildspec.yml b/buildspec.yml index e0d2ad6..292a397 100644 --- a/buildspec.yml +++ b/buildspec.yml @@ -6,6 +6,7 @@ phases: - echo Entered the install phase... - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 & - timeout 15 sh -c "until docker info; do echo .; sleep 1; done" + - docker pull quay.io/jlsherri/client-rhel9 finally: - echo This always runs even if the update or install command fails pre_build: From ddae3abc0884d39587c420920446453a2acc766d Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 25 Feb 2025 16:19:48 -0500 Subject: [PATCH 05/17] pull image if needed --- buildspec.yml | 1 - tests/helpers/containers.tsx | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/buildspec.yml b/buildspec.yml index 292a397..e0d2ad6 100644 --- a/buildspec.yml +++ b/buildspec.yml @@ -6,7 +6,6 @@ phases: - echo Entered the install phase... - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2 & - timeout 15 sh -c "until docker info; do echo .; sleep 1; done" - - docker pull quay.io/jlsherri/client-rhel9 finally: - echo This always runs even if the update or install command fails pre_build: diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index 1f88ac9..4295595 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -19,6 +19,7 @@ export const startContainer = async ( containerName: string, imageName: string ) => { + await pullImage(imageName); console.log("starting container " + containerName); const container = await docker().createContainer({ Image: imageName, @@ -27,6 +28,16 @@ export const startContainer = async ( return container?.start(); }; +const pullImage = async (imageName: string) => { + const images = await docker().listImages(); + for (var image in images) { + if (image == imageName) { + return; + } + } + return docker().pull(imageName); +}; + /* * starts a container and kills one if it already exists with the same name */ From 74989c6d84078af4e8dd394aac8f68f2e12fea1e Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 25 Feb 2025 17:34:46 -0500 Subject: [PATCH 06/17] pull container before running it --- tests/helpers/containers.tsx | 8 +++++--- tests/helpers/rhsmClient.tsx | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index 4295595..a724c90 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -30,12 +30,14 @@ export const startContainer = async ( const pullImage = async (imageName: string) => { const images = await docker().listImages(); - for (var image in images) { - if (image == imageName) { + for (var image of images) { + if ((image.RepoTags ? image.RepoTags : []).includes(imageName)) { return; } } - return docker().pull(imageName); + await docker().pull(imageName); + await sleep(500); + await pullImage(imageName); }; /* diff --git a/tests/helpers/rhsmClient.tsx b/tests/helpers/rhsmClient.tsx index d742643..151a585 100644 --- a/tests/helpers/rhsmClient.tsx +++ b/tests/helpers/rhsmClient.tsx @@ -4,8 +4,8 @@ import { killContainer, runCommand, startNewContainer } from "./containers"; export type OSVersion = "rhel9" | "rhel8"; const RemoteImages = { - rhel9: "quay.io/jlsherri/client-rhel9", - rhel8: "localhost/client-rhel9", + rhel9: "quay.io/jlsherri/client-rhel9:latest", + rhel8: "localhost/client-rhel9:latest", }; export class RHSMClient { From d5820dd7e3b1715b12419cc2dd0cf429d25eab61 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 25 Feb 2025 17:48:29 -0500 Subject: [PATCH 07/17] wait for container to be running --- tests/helpers/containers.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index a724c90..466cff5 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -48,8 +48,8 @@ export const startNewContainer = async ( imageName: string ) => { await killContainer(containerName); - return await startContainer(containerName, imageName); - //await waitForContainer(containerName) + await startContainer(containerName, imageName); + await waitForContainer(containerName); }; async function sleep(ms: number): Promise { From c6d6aa839b02f1b896bc0499e7d5f3a0e4f55109 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 25 Feb 2025 18:25:20 -0500 Subject: [PATCH 08/17] wait for running --- tests/helpers/containers.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index 466cff5..0b1b58f 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -49,7 +49,7 @@ export const startNewContainer = async ( ) => { await killContainer(containerName); await startContainer(containerName, imageName); - await waitForContainer(containerName); + await waitForContainerRunning(containerName); }; async function sleep(ms: number): Promise { @@ -61,12 +61,24 @@ const waitForContainer = async (name: string): Promise => { var waited = 10; while (container == undefined && waited > 0) { waited -= 1; - await sleep(1000); + await sleep(500); container = await getContainer(name); } return container; }; +const waitForContainerRunning = async ( + name: string +): Promise => { + var container = await getContainerInfo(name); + var waited = 10; + while (container?.State !== "running" && waited > 0) { + waited -= 1; + await sleep(500); + container = await getContainerInfo(name); + } +}; + const getContainerInfo = async (name: string) => { const containers = await docker().listContainers({ all: true }); From 86f85342cfe9c588c1c681134ca262e145bb86ef Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Wed, 26 Feb 2025 11:47:14 -0500 Subject: [PATCH 09/17] use priv containers --- tests/helpers/containers.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index 0b1b58f..e83717a 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -24,12 +24,18 @@ export const startContainer = async ( const container = await docker().createContainer({ Image: imageName, name: containerName, + HostConfig: { + Privileged: true, + }, }); return container?.start(); }; -const pullImage = async (imageName: string) => { +const pullImage = async (imageName: string, count?: number) => { const images = await docker().listImages(); + if (count == 0) { + return; + } for (var image of images) { if ((image.RepoTags ? image.RepoTags : []).includes(imageName)) { return; @@ -37,7 +43,7 @@ const pullImage = async (imageName: string) => { } await docker().pull(imageName); await sleep(500); - await pullImage(imageName); + await pullImage(imageName, 9); }; /* @@ -49,7 +55,7 @@ export const startNewContainer = async ( ) => { await killContainer(containerName); await startContainer(containerName, imageName); - await waitForContainerRunning(containerName); + //await waitForContainerRunning(containerName); }; async function sleep(ms: number): Promise { From 2b3a44d3dcb05bdd1c2497283ad86e3ddef1c173 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Wed, 26 Feb 2025 13:46:23 -0500 Subject: [PATCH 10/17] add timeouts --- tests/helpers/containers.tsx | 23 +++++++++++++--- tests/helpers/rhsmClient.tsx | 52 +++++++++++++++++++++++++++++------- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index e83717a..25e6ca1 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -1,3 +1,4 @@ +import { time } from "console"; import Dockerode, { Container } from "dockerode"; import { PassThrough } from "stream"; import { finished } from "stream/promises"; @@ -112,7 +113,7 @@ export const killContainer = async (containerName: string) => { return c?.remove(); }; -interface ExecReturn { +export interface ExecReturn { stdout?: string; stderr?: string; exitCode?: number | null; @@ -121,20 +122,36 @@ interface ExecReturn { // Runs a non-interactive command and returns stdout, stderr, and the exit code export const runCommand = async ( containerName: string, - command: string[] + command: string[], + timeout_ms?: number ): Promise => { console.log("Running " + command + " on " + containerName); + + const controller = new AbortController(); + const signal = controller.signal; + + const timeout = setTimeout(() => { + console.error("Timeout reached for command (" + command + ")"); + controller.abort(); + }, timeout_ms || 500); + const c = await getContainer(containerName); const exec = await c?.exec({ Cmd: command, AttachStdout: true, AttachStderr: true, + Privileged: true, + abortSignal: signal, }); if (exec == undefined) { return undefined; } - const execStream = await exec?.start({}); + const execStream = await exec?.start({ + abortSignal: signal, + }); + + clearTimeout(timeout); if (execStream == undefined) { return undefined; } diff --git a/tests/helpers/rhsmClient.tsx b/tests/helpers/rhsmClient.tsx index 151a585..f39030c 100644 --- a/tests/helpers/rhsmClient.tsx +++ b/tests/helpers/rhsmClient.tsx @@ -1,5 +1,10 @@ import { URL } from "url"; -import { killContainer, runCommand, startNewContainer } from "./containers"; +import { + ExecReturn, + killContainer, + runCommand, + startNewContainer, +} from "./containers"; export type OSVersion = "rhel9" | "rhel8"; @@ -22,7 +27,25 @@ export class RHSMClient { return runCommand(this.name, stageConfigureCommand()); } - async Register(activationKey?: string, orgId?: string) { + async RegisterRHC(activationKey?: string, orgId?: string) { + if (!process.env.PROD) { + await this.ConfigureForStage(); + } + if (activationKey == undefined) { + activationKey = process.env.ACTIVATION_KEY_1 || "COULD_NOT_FIND_KEY"; + } + if (orgId == undefined) { + orgId = process.env.ORG_ID_1 || "COULD_NOT_FIND_ORG_ID"; + } + + return runCommand( + this.name, + ["rhc", "connect", "-a", activationKey, "-o", orgId], + 75000 + ); + } + + async RegisterSubMan(activationKey?: string, orgId?: string) { if (!process.env.PROD) { await this.ConfigureForStage(); } @@ -34,15 +57,23 @@ export class RHSMClient { orgId = process.env.ORG_ID_1 || "COULD_NOT_FIND_ORG_ID"; } - return runCommand(this.name, [ - "subscription-manager", - "register", - "--activationkey", - activationKey, - "--org=" + orgId, - "--name", + return runCommand( this.name, - ]); + [ + "subscription-manager", + "register", + "--activationkey", + activationKey, + "--org=" + orgId, + "--name", + this.name, + ], + 75000 + ); + } + + async Exec(command: string[], timeout?: number): Promise { + return runCommand(this.name, command, timeout); } async Unregister() { @@ -65,6 +96,7 @@ const stageConfigureCommand = (): string[] => { "--server.port=443", "--server.prefix=/subscription", "--server.insecure=0", + "--rhsm.baseurl=https://cdn.stage.redhat.com", ]; if (process.env.PROXY !== undefined) { const url = new URL(process.env.PROXY); From 86e7512f813125d29c856fe1b05631dd6a0d74ba Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Wed, 26 Feb 2025 14:14:37 -0500 Subject: [PATCH 11/17] add comments --- tests/helpers/containers.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index 25e6ca1..678b3c2 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -8,14 +8,11 @@ var Docker = require("dockerode"); const util = require("util"); const exec = util.promisify(require("child_process").exec); -const dockerHost = () => { - return process.env.DOCKER_SOCKET!; -}; - const docker = (): Dockerode => { - return new Docker({ socketPath: dockerHost() }); + return new Docker({ socketPath: process.env.DOCKER_SOCKET! }); }; +// Starts a container, should not already be running, image should already be pulled export const startContainer = async ( containerName: string, imageName: string @@ -32,6 +29,7 @@ export const startContainer = async ( return container?.start(); }; +// Pulls an image and waits for it to finish, up to 5 seconds const pullImage = async (imageName: string, count?: number) => { const images = await docker().listImages(); if (count == 0) { @@ -56,7 +54,6 @@ export const startNewContainer = async ( ) => { await killContainer(containerName); await startContainer(containerName, imageName); - //await waitForContainerRunning(containerName); }; async function sleep(ms: number): Promise { @@ -120,6 +117,7 @@ export interface ExecReturn { } // Runs a non-interactive command and returns stdout, stderr, and the exit code +// Defaults to a 500 ms timeout unless timeout is specified export const runCommand = async ( containerName: string, command: string[], From e4186fe053385803abbc115f81072a312915cd98 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Fri, 28 Feb 2025 12:13:21 -0500 Subject: [PATCH 12/17] add comments and examples --- tests/helpers/containers.example.ts | 29 ++++++++++++ tests/helpers/containers.tsx | 70 +++++++++++++++++++---------- tests/helpers/rhsmClient.example.ts | 38 ++++++++++++++++ tests/helpers/rhsmClient.tsx | 43 ++++++++++++++++++ 4 files changed, 157 insertions(+), 23 deletions(-) create mode 100644 tests/helpers/containers.example.ts create mode 100644 tests/helpers/rhsmClient.example.ts diff --git a/tests/helpers/containers.example.ts b/tests/helpers/containers.example.ts new file mode 100644 index 0000000..6e7f187 --- /dev/null +++ b/tests/helpers/containers.example.ts @@ -0,0 +1,29 @@ +import { + killContainer, + runCommand, + startNewContainer, +} from "../helpers/containers"; +import { test, expect } from "@playwright/test"; + +test("Test container", async ({}) => { + await startNewContainer( + "my_container", + "quay.io/jlsherri/client-rhel9:latest" + ); + + const stream = await runCommand("my_container", ["ls", "-l"]); + if (stream != undefined) { + console.log(stream.stdout); + console.log(stream.stderr); + console.log(stream.exitCode); + } + + const stream2 = await runCommand("my_container", ["ls", "-z"]); + if (stream2 != undefined) { + console.log(stream2.stdout); + console.log(stream2.stderr); + console.log(stream2.exitCode); + } + + await killContainer("my_container"); +}); diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index 678b3c2..eb093bf 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -12,11 +12,31 @@ const docker = (): Dockerode => { return new Docker({ socketPath: process.env.DOCKER_SOCKET! }); }; -// Starts a container, should not already be running, image should already be pulled -export const startContainer = async ( +/** + * starts a container, killing the existing one if its present + * + * @param containerName customizable name ("my_container)" to give to your container. Could be the test name, or something linking it to the test. + * @param imageName full image name and tag: "localhost/my_image:latest" + */ +export const startNewContainer = async ( containerName: string, imageName: string ) => { + await killContainer(containerName); + await startContainer(containerName, imageName); +}; + +async function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +/** + * Starts a container, should not already be running, image should already be pulled + * @param containerName customizable name ("my_container)" to give to your container. Could be the test name, or something linking it to the test. + * @param imageName full image name and tag: "localhost/my_image:latest" + * @returns + */ +const startContainer = async (containerName: string, imageName: string) => { await pullImage(imageName); console.log("starting container " + containerName); const container = await docker().createContainer({ @@ -29,10 +49,15 @@ export const startContainer = async ( return container?.start(); }; -// Pulls an image and waits for it to finish, up to 5 seconds -const pullImage = async (imageName: string, count?: number) => { +/** + * Pulls an image and waits for it to finish, up to 5 seconds + * + * @param imageName the full image name (localhost/my-image:latest) + * @param retryCount number of times to retry the pull until its successful (defaults to 5) + */ +const pullImage = async (imageName: string, retryCount?: number) => { const images = await docker().listImages(); - if (count == 0) { + if (retryCount == 0) { return; } for (var image of images) { @@ -42,24 +67,9 @@ const pullImage = async (imageName: string, count?: number) => { } await docker().pull(imageName); await sleep(500); - await pullImage(imageName, 9); -}; - -/* - * starts a container and kills one if it already exists with the same name - */ -export const startNewContainer = async ( - containerName: string, - imageName: string -) => { - await killContainer(containerName); - await startContainer(containerName, imageName); + await pullImage(imageName, (retryCount || 5) - 1); }; -async function sleep(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - const waitForContainer = async (name: string): Promise => { var container = await getContainer(name); var waited = 10; @@ -101,13 +111,18 @@ const getContainer = async (name: string): Promise => { } }; +/** + * Kills the running container and deletes it + * @param containerName the user provided container to kill + * @returns + */ export const killContainer = async (containerName: string) => { const info = await getContainerInfo(containerName); const c = await getContainer(containerName); if (info?.State == "running") { await c?.kill(); } - return c?.remove(); + await c?.remove(); }; export interface ExecReturn { @@ -116,8 +131,17 @@ export interface ExecReturn { exitCode?: number | null; } -// Runs a non-interactive command and returns stdout, stderr, and the exit code +// // Defaults to a 500 ms timeout unless timeout is specified + +/** + * Runs a non-interactive command and returns stdout, stderr, and the exit code + * + * @param containerName the human readable container name to execute the command + * @param command the command to execute + * @param timeout_ms timeout (in milliseconds) the command should execute in (defaults to 500ms) + * @returns ExecReturn containing stdout, stderr, exitCode + */ export const runCommand = async ( containerName: string, command: string[], diff --git a/tests/helpers/rhsmClient.example.ts b/tests/helpers/rhsmClient.example.ts new file mode 100644 index 0000000..53fd305 --- /dev/null +++ b/tests/helpers/rhsmClient.example.ts @@ -0,0 +1,38 @@ +import { test, expect } from "@playwright/test"; +import { RHSMClient } from "./rhsmClient"; + +test("RHSM client", async ({}, testInfo) => { + // change the test timeout as registering a client can be slow + testInfo.setTimeout(5 * 60 * 1000); // Five minutes + + // Create a client with a test-specific name + const client = new RHSMClient("RHSMClientTest"); + + // Start the rhel9 container + await client.Boot("rhel9"); + + // Register, overriding the default key and org + const reg = await client.RegisterSubMan("my_activation_key", "my_org_id"); + if (reg?.exitCode != 0) { + console.log(reg?.stdout); + console.log(reg?.stderr); + } + expect(reg?.exitCode).toBe(0); + + // vim-enhanced shouldn't be installed + const notExist = await client.Exec(["rpm", "-q", "vim-enhanced"]); + expect(notExist?.exitCode).not.toBe(0); + + // Install vim-enhanced, expect it to finish in 60 seconds + const yumInstall = await client.Exec( + ["yum", "install", "-y", "vim-enhanced"], + 60000 + ); + expect(yumInstall?.exitCode).toBe(0); + + // Now vim-enhanced should be installed + const exist = await client.Exec(["rpm", "-q", "vim-enhanced"]); + expect(exist?.exitCode).toBe(0); + + await client.Destroy(); +}); diff --git a/tests/helpers/rhsmClient.tsx b/tests/helpers/rhsmClient.tsx index f39030c..26c5290 100644 --- a/tests/helpers/rhsmClient.tsx +++ b/tests/helpers/rhsmClient.tsx @@ -6,27 +6,51 @@ import { startNewContainer, } from "./containers"; +/** + * Supported Operating System versions + */ export type OSVersion = "rhel9" | "rhel8"; +/** + * List of containers to use + */ const RemoteImages = { rhel9: "quay.io/jlsherri/client-rhel9:latest", rhel8: "localhost/client-rhel9:latest", }; +/** + * Class to start and manage a registered RHSM/insights client + */ export class RHSMClient { name: string; constructor(name: string) { this.name = name; } + /** + * Starts an rhsm client contianer + * @param version OS and version to boot + * @returns + */ async Boot(version: OSVersion) { return startNewContainer(this.name, RemoteImages[version]); } + /** + * configures this client for stage registration + * @returns + */ async ConfigureForStage() { return runCommand(this.name, stageConfigureCommand()); } + /** + * Registers to configured environment using RHC + * @param activationKey key to register with. Defaults to $ACTIVATION_KEY_1 + * @param orgId orgId to register with. Defaults to $ORG_ID_1 + * @returns + */ async RegisterRHC(activationKey?: string, orgId?: string) { if (!process.env.PROD) { await this.ConfigureForStage(); @@ -45,6 +69,12 @@ export class RHSMClient { ); } + /** + * Register using subscription-manager (won't show up in insights) + * @param activationKey key to register with. Defaults to $ACTIVATION_KEY_1 + * @param orgId orgId to register with. Defaults to $ORG_ID_1 + * @returns + */ async RegisterSubMan(activationKey?: string, orgId?: string) { if (!process.env.PROD) { await this.ConfigureForStage(); @@ -72,14 +102,27 @@ export class RHSMClient { ); } + /** + * Run an arbitrary command on the host + * @param command Command to run + * @param timeout Timeout in ms to cancel the command, defaults to 500ms + * @returns + */ async Exec(command: string[], timeout?: number): Promise { return runCommand(this.name, command, timeout); } + /** + * Unregister with subscription-manager + * @returns + */ async Unregister() { return runCommand(this.name, ["subscription-manager", "unregister"]); } + /** + * Unregister and destroy the client container + */ async Destroy() { const cmd = await this.Unregister(); console.log(cmd?.stdout); From 15e153e65b7fa7fa4066f6c6e9f3dedb5eb497e5 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Mon, 3 Mar 2025 10:56:49 -0500 Subject: [PATCH 13/17] switch to GH secrets --- .github/workflows/stageTestAction.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stageTestAction.yml b/.github/workflows/stageTestAction.yml index 43ff6db..995a43c 100644 --- a/.github/workflows/stageTestAction.yml +++ b/.github/workflows/stageTestAction.yml @@ -47,8 +47,8 @@ jobs: echo "PROXY=$PROXY" >> .env echo "TOKEN=apple" >> .env echo "CI=true" >> .env - echo "ORG_ID_1=$STAGE_ORG_ID" >> .env - echo "ACTIVATION_KEY_1=$STAGE_ACTIVATION_KEY" >> .env + echo "ORG_ID_1=${{ secrets.STAGE_ORG_ID }}" >> .env + echo "ACTIVATION_KEY_1=${{ secrets.STAGE_ACTIVATION_KEY }}" >> .env echo "DOCKER_SOCKET=/var/run/docker.sock" >> .env - name: Set up Node.js uses: actions/setup-node@v2 From 65e582fc82c2ff75a15f9f6e1b59c75ce9092052 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Mon, 3 Mar 2025 17:57:35 -0500 Subject: [PATCH 14/17] wait for pull a bit smarter --- tests/helpers/containers.tsx | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index eb093bf..fb0cc0f 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -53,21 +53,37 @@ const startContainer = async (containerName: string, imageName: string) => { * Pulls an image and waits for it to finish, up to 5 seconds * * @param imageName the full image name (localhost/my-image:latest) - * @param retryCount number of times to retry the pull until its successful (defaults to 5) + * @param retryCount number of times to retry the pull until its successful (defaults to 3) + * @param waitTime amount of time to wait for each pull */ -const pullImage = async (imageName: string, retryCount?: number) => { - const images = await docker().listImages(); +const pullImage = async ( + imageName: string, + retryCount?: number, + waitTime?: number +) => { + var sleepTime = waitTime || 10000; if (retryCount == 0) { return; } + await docker().pull(imageName); + while (sleepTime > 0) { + if (await imagePresent(imageName)) { + return true; + } + sleep(1000); + sleepTime -= 1000; + } + await pullImage(imageName, (retryCount || 3) - 1, waitTime); +}; + +const imagePresent = async (imageName: string): Promise => { + const images = await docker().listImages(); for (var image of images) { if ((image.RepoTags ? image.RepoTags : []).includes(imageName)) { - return; + return true; } } - await docker().pull(imageName); - await sleep(500); - await pullImage(imageName, (retryCount || 5) - 1); + return false; }; const waitForContainer = async (name: string): Promise => { From 4f4821939f22a663706606aa6ff72d0b6215c9fc Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Tue, 4 Mar 2025 09:27:56 -0500 Subject: [PATCH 15/17] await for sleep --- tests/helpers/containers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers/containers.tsx b/tests/helpers/containers.tsx index fb0cc0f..52dee9a 100644 --- a/tests/helpers/containers.tsx +++ b/tests/helpers/containers.tsx @@ -70,7 +70,7 @@ const pullImage = async ( if (await imagePresent(imageName)) { return true; } - sleep(1000); + await sleep(1000); sleepTime -= 1000; } await pullImage(imageName, (retryCount || 3) - 1, waitTime); From a2b5754b127e7ee8ab430c18020ceb52c47f5de3 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Mon, 10 Mar 2025 10:40:07 -0400 Subject: [PATCH 16/17] switch to new quay repos --- tests/helpers/rhsmClient.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/helpers/rhsmClient.tsx b/tests/helpers/rhsmClient.tsx index 26c5290..bd97249 100644 --- a/tests/helpers/rhsmClient.tsx +++ b/tests/helpers/rhsmClient.tsx @@ -15,8 +15,9 @@ export type OSVersion = "rhel9" | "rhel8"; * List of containers to use */ const RemoteImages = { - rhel9: "quay.io/jlsherri/client-rhel9:latest", - rhel8: "localhost/client-rhel9:latest", + rhel9: "quay.io/swadeley/ubi9_rhc_prod:latest", + rhel8: "quay.io/swadeley/ubi8_rhc_prod:latest", + rhel9dev: "quay.io/swadeley/ubi9_rhc_dev_prod:latest", }; /** From a7e247f0232cb1b37bf055a869953b7a6ee9c256 Mon Sep 17 00:00:00 2001 From: Justin Sherrill Date: Wed, 12 Mar 2025 07:55:08 -0400 Subject: [PATCH 17/17] Revert "switch to GH secrets" This reverts commit 0b5efac807ce5ac9db2084c3d6ef840dc7a86ce6. --- .github/workflows/stageTestAction.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stageTestAction.yml b/.github/workflows/stageTestAction.yml index 995a43c..43ff6db 100644 --- a/.github/workflows/stageTestAction.yml +++ b/.github/workflows/stageTestAction.yml @@ -47,8 +47,8 @@ jobs: echo "PROXY=$PROXY" >> .env echo "TOKEN=apple" >> .env echo "CI=true" >> .env - echo "ORG_ID_1=${{ secrets.STAGE_ORG_ID }}" >> .env - echo "ACTIVATION_KEY_1=${{ secrets.STAGE_ACTIVATION_KEY }}" >> .env + echo "ORG_ID_1=$STAGE_ORG_ID" >> .env + echo "ACTIVATION_KEY_1=$STAGE_ACTIVATION_KEY" >> .env echo "DOCKER_SOCKET=/var/run/docker.sock" >> .env - name: Set up Node.js uses: actions/setup-node@v2