diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index b2e9bdf..f4e9a48 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -49,13 +49,20 @@ jobs: LATEST_TAG=$(curl -s https://api.github.com/repos/fosrl/gerbil/tags | jq -r '.[0].name') echo "LATEST_GERBIL_TAG=$LATEST_TAG" >> $GITHUB_ENV + - name: Pull latest Badger version + id: get-badger-tag + run: | + LATEST_TAG=$(curl -s https://api.github.com/repos/fosrl/badger/tags | jq -r '.[0].name') + echo "LATEST_BADGER_TAG=$LATEST_TAG" >> $GITHUB_ENV + - name: Update install/main.go run: | PANGOLIN_VERSION=${{ env.TAG }} GERBIL_VERSION=${{ env.LATEST_GERBIL_TAG }} sed -i "s/config.PangolinVersion = \".*\"/config.PangolinVersion = \"$PANGOLIN_VERSION\"/" install/main.go sed -i "s/config.GerbilVersion = \".*\"/config.GerbilVersion = \"$GERBIL_VERSION\"/" install/main.go - echo "Updated install/main.go with Pangolin version $PANGOLIN_VERSION and Gerbil version $GERBIL_VERSION" + sed -i "s/config.BadgerVersion = \".*\"/config.BadgerVersion = \"$BADGER_VERSION\"/" install/main.go + echo "Updated install/main.go with Pangolin version $PANGOLIN_VERSION, Gerbil version $GERBIL_VERSION, and Badger version $BADGER_VERSION" cat install/main.go - name: Build and push Docker images diff --git a/install/main.go b/install/main.go index 7436c55..da22096 100644 --- a/install/main.go +++ b/install/main.go @@ -21,6 +21,7 @@ import ( func loadVersions(config *Config) { config.PangolinVersion = "replaceme" config.GerbilVersion = "replaceme" + // config.BadgerVersion = "replaceme" } //go:embed fs/* @@ -487,4 +488,4 @@ func pullAndStartContainers() error { } return nil -} \ No newline at end of file +} diff --git a/server/setup/scripts/1.0.0-beta9.ts b/server/setup/scripts/1.0.0-beta9.ts index f82f701..32fd8e3 100644 --- a/server/setup/scripts/1.0.0-beta9.ts +++ b/server/setup/scripts/1.0.0-beta9.ts @@ -20,216 +20,204 @@ import { fromZodError } from "zod-validation-error"; export default async function migration() { console.log("Running setup script 1.0.0-beta.9..."); - try { - await db.transaction(async (trx) => { - trx.run(sql`UPDATE ${users} SET email = LOWER(email);`); - trx.run( - sql`UPDATE ${emailVerificationCodes} SET email = LOWER(email);` - ); - trx.run( - sql`UPDATE ${passwordResetTokens} SET email = LOWER(email);` - ); - trx.run(sql`UPDATE ${userInvites} SET email = LOWER(email);`); - trx.run(sql`UPDATE ${resourceWhitelist} SET email = LOWER(email);`); - trx.run(sql`UPDATE ${resourceOtp} SET email = LOWER(email);`); - }); - } catch (error) { - console.log( - "We were unable to make all emails lower case in the database. You can safely ignore this error." - ); - console.error(error); - } + await db.transaction(async (trx) => { + try { + // Determine which config file exists + const filePaths = [configFilePath1, configFilePath2]; + let filePath = ""; + for (const path of filePaths) { + if (fs.existsSync(path)) { + filePath = path; + break; + } + } - try { - await db.transaction(async (trx) => { - - const resourcesAll = await trx.select({ + if (!filePath) { + throw new Error( + `No config file found (expected config.yml or config.yaml).` + ); + } + + // Read and parse the YAML file + let rawConfig: any; + const fileContents = fs.readFileSync(filePath, "utf8"); + rawConfig = yaml.load(fileContents); + + rawConfig.server.resource_session_request_param = + "p_session_request"; + rawConfig.server.session_cookie_name = "p_session_token"; // rename to prevent conflicts + delete rawConfig.server.resource_session_cookie_name; + + // Write the updated YAML back to the file + const updatedYaml = yaml.dump(rawConfig); + fs.writeFileSync(filePath, updatedYaml, "utf8"); + } catch (e) { + console.log( + `Failed to add resource_session_request_param to config. Please add it manually. https://docs.fossorial.io/Pangolin/Configuration/config` + ); + trx.rollback(); + return; + } + + try { + const traefikPath = path.join( + APP_PATH, + "traefik", + "traefik_config.yml" + ); + + // Define schema for traefik config validation + const schema = z.object({ + entryPoints: z + .object({ + websecure: z + .object({ + address: z.string(), + transport: z + .object({ + respondingTimeouts: z.object({ + readTimeout: z.string() + }) + }) + .optional() + }) + .optional() + }) + .optional(), + experimental: z.object({ + plugins: z.object({ + badger: z.object({ + moduleName: z.string(), + version: z.string() + }) + }) + }) + }); + + const traefikFileContents = fs.readFileSync(traefikPath, "utf8"); + const traefikConfig = yaml.load(traefikFileContents) as any; + + const parsedConfig = schema.safeParse(traefikConfig); + + if (parsedConfig.success) { + // Ensure websecure entrypoint exists + if (traefikConfig.entryPoints?.websecure) { + // Add transport configuration + traefikConfig.entryPoints.websecure.transport = { + respondingTimeouts: { + readTimeout: "30m" + } + }; + } + + traefikConfig.experimental.plugins.badger.version = + "v1.0.0-beta.3"; + + const updatedTraefikYaml = yaml.dump(traefikConfig); + fs.writeFileSync(traefikPath, updatedTraefikYaml, "utf8"); + + console.log( + "Updated the version of Badger in your Traefik configuration to v1.0.0-beta.3 and added readTimeout to websecure entrypoint in your Traefik configuration.." + ); + } else { + console.log(fromZodError(parsedConfig.error)); + console.log( + "We were unable to update the version of Badger in your Traefik configuration. Please update it manually to at least v1.0.0-beta.3. https://github.com/fosrl/badger" + ); + } + } catch (e) { + console.log( + "We were unable to update the version of Badger in your Traefik configuration. Please update it manually to at least v1.0.0-beta.3. https://github.com/fosrl/badger" + ); + trx.rollback(); + return; + } + + trx.run(sql`UPDATE ${users} SET email = LOWER(email);`); + trx.run( + sql`UPDATE ${emailVerificationCodes} SET email = LOWER(email);` + ); + trx.run(sql`UPDATE ${passwordResetTokens} SET email = LOWER(email);`); + trx.run(sql`UPDATE ${userInvites} SET email = LOWER(email);`); + trx.run(sql`UPDATE ${resourceWhitelist} SET email = LOWER(email);`); + trx.run(sql`UPDATE ${resourceOtp} SET email = LOWER(email);`); + + const resourcesAll = await trx + .select({ resourceId: resources.resourceId, fullDomain: resources.fullDomain, subdomain: resources.subdomain - }).from(resources); + }) + .from(resources); - trx.run(`DROP INDEX resources_fullDomain_unique;`) - trx.run(`ALTER TABLE resources + trx.run(`DROP INDEX resources_fullDomain_unique;`); + trx.run(`ALTER TABLE resources DROP COLUMN fullDomain; - `) - trx.run(`ALTER TABLE resources + `); + trx.run(`ALTER TABLE resources DROP COLUMN subdomain; - `) - trx.run(sql`ALTER TABLE resources + `); + trx.run(sql`ALTER TABLE resources ADD COLUMN fullDomain TEXT; - `) - trx.run(sql`ALTER TABLE resources + `); + trx.run(sql`ALTER TABLE resources ADD COLUMN subdomain TEXT; - `) - trx.run(sql`ALTER TABLE resources + `); + trx.run(sql`ALTER TABLE resources ADD COLUMN http INTEGER DEFAULT true NOT NULL; - `) - trx.run(sql`ALTER TABLE resources + `); + trx.run(sql`ALTER TABLE resources ADD COLUMN protocol TEXT DEFAULT 'tcp' NOT NULL; - `) - trx.run(sql`ALTER TABLE resources + `); + trx.run(sql`ALTER TABLE resources ADD COLUMN proxyPort INTEGER; - `) + `); - // write the new fullDomain and subdomain values back to the database - for (const resource of resourcesAll) { - await trx.update(resources).set({ + // write the new fullDomain and subdomain values back to the database + for (const resource of resourcesAll) { + await trx + .update(resources) + .set({ fullDomain: resource.fullDomain, subdomain: resource.subdomain - }).where(eq(resources.resourceId, resource.resourceId)); - } + }) + .where(eq(resources.resourceId, resource.resourceId)); + } - const targetsAll = await trx.select({ + const targetsAll = await trx + .select({ targetId: targets.targetId, method: targets.method - }).from(targets); - - trx.run(`ALTER TABLE targets - DROP COLUMN method; - `) - trx.run(`ALTER TABLE targets - DROP COLUMN protocol; - `) - trx.run(sql`ALTER TABLE targets - ADD COLUMN method TEXT; - `) - - // write the new method and protocol values back to the database - for (const target of targetsAll) { - await trx.update(targets).set({ - method: target.method - }).where(eq(targets.targetId, target.targetId)); - } - - }); - } catch (error) { - console.log( - "We were unable to make the changes to the targets and resources tables." - ); - throw error; - } - - try { - // Determine which config file exists - const filePaths = [configFilePath1, configFilePath2]; - let filePath = ""; - for (const path of filePaths) { - if (fs.existsSync(path)) { - filePath = path; - break; - } - } - - if (!filePath) { - throw new Error( - `No config file found (expected config.yml or config.yaml).` - ); - } - - // Read and parse the YAML file - let rawConfig: any; - const fileContents = fs.readFileSync(filePath, "utf8"); - rawConfig = yaml.load(fileContents); - - rawConfig.server.resource_session_request_param = "p_session_request"; - rawConfig.server.session_cookie_name = "p_session_token"; // rename to prevent conflicts - delete rawConfig.server.resource_session_cookie_name; - - // Write the updated YAML back to the file - const updatedYaml = yaml.dump(rawConfig); - fs.writeFileSync(filePath, updatedYaml, "utf8"); - } catch (e) { - console.log( - `Failed to add resource_session_request_param to config. Please add it manually. https://docs.fossorial.io/Pangolin/Configuration/config` - ); - throw e; - } - - try { - const traefikPath = path.join( - APP_PATH, - "traefik", - "traefik_config.yml" - ); - - // Define schema for traefik config validation - const schema = z.object({ - entryPoints: z - .object({ - websecure: z - .object({ - address: z.string(), - transport: z - .object({ - respondingTimeouts: z.object({ - readTimeout: z.string() - }) - }) - .optional() - }) - .optional() - }) - .optional(), - experimental: z.object({ - plugins: z.object({ - badger: z.object({ - moduleName: z.string(), - version: z.string() - }) - }) }) - }); + .from(targets); - const traefikFileContents = fs.readFileSync(traefikPath, "utf8"); - const traefikConfig = yaml.load(traefikFileContents) as any; + trx.run(`ALTER TABLE targets + DROP COLUMN method; + `); + trx.run(`ALTER TABLE targets + DROP COLUMN protocol; + `); + trx.run(sql`ALTER TABLE targets + ADD COLUMN method TEXT; + `); - const parsedConfig = schema.safeParse(traefikConfig); - - if (!parsedConfig.success) { - throw new Error(fromZodError(parsedConfig.error).toString()); + // write the new method and protocol values back to the database + for (const target of targetsAll) { + await trx + .update(targets) + .set({ + method: target.method + }) + .where(eq(targets.targetId, target.targetId)); } - // Ensure websecure entrypoint exists - if (traefikConfig.entryPoints?.websecure) { - // Add transport configuration - traefikConfig.entryPoints.websecure.transport = { - respondingTimeouts: { - readTimeout: "30m" - } - }; - } - - traefikConfig.experimental.plugins.badger.version = "v1.0.0-beta.3"; - - const updatedTraefikYaml = yaml.dump(traefikConfig); - fs.writeFileSync(traefikPath, updatedTraefikYaml, "utf8"); - - console.log( - "Updated the version of Badger in your Traefik configuration to v1.0.0-beta.3 and added readTimeout to websecure entrypoint in your Traefik configuration.." + trx.run( + sql`ALTER TABLE 'resourceSessions' ADD 'isRequestToken' integer;` ); - } catch (e) { - console.log( - "We were unable to update the version of Badger in your Traefik configuration. Please update it manually to at least v1.0.0-beta.3. https://github.com/fosrl/badger" + trx.run( + sql`ALTER TABLE 'resourceSessions' ADD 'userSessionId' text REFERENCES session(id);` ); - throw e; - } - - try { - await db.transaction(async (trx) => { - trx.run( - sql`ALTER TABLE 'resourceSessions' ADD 'isRequestToken' integer;` - ); - trx.run( - sql`ALTER TABLE 'resourceSessions' ADD 'userSessionId' text REFERENCES session(id);` - ); - }); - } catch (e) { - console.log( - "We were unable to add columns to the resourceSessions table." - ); - throw e; - } + }); console.log("Done."); }