summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2025-05-12 09:40:12 -0700
committerElizabeth Alexander Hunt <me@liz.coffee>2025-05-12 09:54:58 -0700
commit723fa00cb14513eb1a517728d4464c4f148a29cc (patch)
treed32e2f725397d41b3ad7f886d61c16458dde5b37 /utils
parent30729a0cf707d9022bae0a7baaba77379dc31fd5 (diff)
downloadci-723fa00cb14513eb1a517728d4464c4f148a29cc.tar.gz
ci-723fa00cb14513eb1a517728d4464c4f148a29cc.zip
The big refactor
Diffstat (limited to 'utils')
-rw-r--r--utils/env.ts2
-rw-r--r--utils/logger.ts6
-rw-r--r--utils/mod.ts2
-rw-r--r--utils/run.ts2
-rw-r--r--utils/secret.ts42
-rw-r--r--utils/trace.ts111
-rw-r--r--utils/validate_identifier.ts8
7 files changed, 151 insertions, 22 deletions
diff --git a/utils/env.ts b/utils/env.ts
index c0cf447..31b7ccf 100644
--- a/utils/env.ts
+++ b/utils/env.ts
@@ -1,5 +1,5 @@
export const getRequiredEnv = (name: string): string => {
const value = Deno.env.get(name);
- if (!value) throw new Error(`${name} environment variable is required`);
+ if (!value) throw new Error(`environment variable "${name}" is required D:`);
return value;
};
diff --git a/utils/logger.ts b/utils/logger.ts
deleted file mode 100644
index e36d249..0000000
--- a/utils/logger.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export const loggerWithPrefix = (prefixSupplier: () => string) => {
- return {
- log: (...args: unknown[]) => console.log(prefixSupplier(), ...args),
- error: (...args: unknown[]) => console.error(prefixSupplier(), ...args),
- };
-};
diff --git a/utils/mod.ts b/utils/mod.ts
index 4e907df..a8a0751 100644
--- a/utils/mod.ts
+++ b/utils/mod.ts
@@ -1,4 +1,4 @@
-export * from "./logger.ts";
+export * from "./trace.ts";
export * from "./env.ts";
export * from "./run.ts";
export * from "./secret.ts";
diff --git a/utils/run.ts b/utils/run.ts
index f06ef97..60ae1e6 100644
--- a/utils/run.ts
+++ b/utils/run.ts
@@ -15,7 +15,7 @@ export const getStdout = async (
const stdoutText = new TextDecoder().decode(stdout);
const stderrText = new TextDecoder().decode(stderr);
- if (code !== 0) throw new Error(`Command failed\n${stderrText}`);
+ if (code !== 0) throw new Error(`command failed\n${stderrText}`);
return stdoutText;
};
diff --git a/utils/secret.ts b/utils/secret.ts
index eb2054b..0faa97c 100644
--- a/utils/secret.ts
+++ b/utils/secret.ts
@@ -1,35 +1,47 @@
-import { getRequiredEnv, getStdout, loggerWithPrefix } from "./mod.ts";
+import {
+ getRequiredEnv,
+ getStdout,
+ loggerWithPrefix,
+ type PrefixLogger,
+} from "./mod.ts";
-const logger = loggerWithPrefix(() =>
- `[${new Date().toISOString()}] [BitwardenSession]`
-);
export class BitwardenSession {
private readonly sessionInitializer: Promise<string>;
+ private readonly logger: PrefixLogger;
- constructor(server = getRequiredEnv("BW_SERVER")) {
+ constructor(
+ server = getRequiredEnv("BW_SERVER"),
+ logger = loggerWithPrefix(),
+ ) {
["BW_CLIENTID", "BW_CLIENTSECRET"].forEach(getRequiredEnv);
+ const instanceId = crypto.randomUUID().split("-").at(0);
+ this.logger = logger.withAdditionalPrefix(() =>
+ `[BitwardenSession.instance.${instanceId}]`
+ );
+
this.sessionInitializer = getStdout(
`bw config server ${server} --quiet`,
)
.then(() => {
- logger.log("Logging in via API");
+ this.logger.log("logging in via api (˘ω˘)");
return getStdout(`bw login --apikey --quiet`);
})
.then(() => {
- logger.log("Unlocking vault in session");
+ this.logger.log("unlocking the secret vault~ (◕ᴗ◕✿)");
return getStdout(`bw unlock --passwordenv BW_PASSWORD --raw`);
})
.then((session) => {
- logger.log(`Session ${session}`);
- return session.trim();
+ const _session = session.trim();
+ this.logger.log(`got my session key (>ᴗ<) ${_session}`);
+ return _session;
});
}
public async getItem<T extends LoginItem | SecureNote>(
secretName: string,
): Promise<T> {
- logger.log(`Finding secret ${secretName}`);
+ this.logger.log(`looking for your secret ${secretName} (⑅˘꒳˘)`);
return await this.sessionInitializer.then((session) =>
getStdout(`bw list items`, {
env: {
@@ -39,8 +51,12 @@ export class BitwardenSession {
).then((items) => JSON.parse(items)).then((items) =>
items.find(({ name }: { name: string }) => name === secretName)
).then((item) => {
- if (!item) throw new Error("Could not find bitwarden item " + secretName);
- logger.log(`Found secret: ${secretName}`);
+ if (!item) {
+ throw new Error(
+ "couldn't find the bitwarden item " + secretName + " (。•́︿•̀。)",
+ );
+ }
+ this.logger.log(`yay! found secret: ${secretName} (*ˊᗜˋ*)`);
return item;
});
}
@@ -49,7 +65,7 @@ export class BitwardenSession {
return await this.sessionInitializer.then((session) =>
getStdout(`bw lock`, { env: { BW_SESSION: session } })
).then(() => {
- logger.log("Locked session");
+ this.logger.log("all locked up and secure now~ (。•̀ᴗ-)✧");
});
}
}
diff --git a/utils/trace.ts b/utils/trace.ts
new file mode 100644
index 0000000..737aa60
--- /dev/null
+++ b/utils/trace.ts
@@ -0,0 +1,111 @@
+export interface Logger {
+ log: (...args: unknown[]) => void;
+ debug: (...args: unknown[]) => void;
+ warn: (...args: unknown[]) => void;
+ error: (...args: unknown[]) => void;
+}
+
+type Supplier<T> = () => T;
+type TraceSupplier = Supplier<string>;
+export interface ITraceableLogger<L extends ITraceableLogger<L>>
+ extends Logger {
+ addTracer: (traceSupplier: TraceSupplier) => L;
+}
+
+export type ITraceableTuple<T> = [T, TraceSupplier];
+export type ITraceableMapper<T, L extends ITraceableLogger<L>, U> = (
+ t: ITraceable<T, L>,
+) => U;
+export interface ITraceable<T, L extends ITraceableLogger<L>> {
+ item: T;
+ logger: L;
+
+ map: <U>(mapper: ITraceableMapper<T, L, U>) => ITraceable<U, L>;
+ bimap: <U>(
+ mapper: ITraceableMapper<T, L, ITraceableTuple<U>>,
+ ) => ITraceable<U, L>;
+ peek: (peek: ITraceableMapper<T, L, void>) => ITraceable<T, L>;
+ flatMap: <U>(mapper: ITraceableMapper<T, L, ITraceable<U, L>>) => ITraceable<U, L>;
+ flatMapAsync<U>(mapper: ITraceableMapper<T, L, Promise<ITraceable<U, L>>>): ITraceable<Promise<U>, L>;
+}
+
+export class TraceableLogger
+ implements ITraceableLogger<TraceableLogger> {
+ private readonly logger: Logger = console;
+ constructor(
+ private readonly traces = [() => `[${new Date().toISOString()}]`],
+ ) {
+ }
+
+ public debug(...args: unknown[]) {
+ this.logger.debug("[DEBUG]", ...this.getPrefix(), args);
+ }
+
+ public log(...args: unknown[]) {
+ this.logger.log("[INFO]", ...this.getPrefix(), args);
+ }
+
+ public warn(...args: unknown[]) {
+ this.logger.warn("[WARN]", ...this.getPrefix(), args);
+ }
+
+ public error(...args: unknown[]) {
+ this.logger.error("[ERROR]", ...this.getPrefix(), args);
+ }
+
+ public addTracer(traceSupplier: TraceSupplier) {
+ return new TraceableLogger(this.traces.concat(traceSupplier));
+ }
+
+ private getPrefix() {
+ return this.traces.map((tracer) => tracer());
+ }
+}
+
+export class TraceableImpl<
+ T,
+ L extends ITraceableLogger<L>,
+> implements ITraceable<T, L> {
+ private constructor(readonly item: T, readonly logger: L) {}
+
+ public map<U>(mapper: ITraceableMapper<T, L, U>) {
+ const result = mapper(this);
+ return new TraceableImpl(result, this.logger);
+ }
+
+ public flatMap<U>(mapper: ITraceableMapper<T, L, ITraceable<U, L>>): ITraceable<U, L> {
+ return mapper(this);
+ }
+
+ public flatMapAsync<U>(mapper: ITraceableMapper<T, L, Promise<ITraceable<U, L>>>): ITraceable<Promise<U>, L> {
+ return new TraceableImpl(mapper(this).then((i) => )
+ }
+
+ public peek(peek: ITraceableMapper<T, L, void>) {
+ peek(this);
+ return this;
+ }
+
+ public bimap<U>(mapper: ITraceableMapper<T, L, ITraceableTuple<U>>) {
+ const [item, trace] = mapper(this);
+ return new TraceableImpl(item, this.logger.addTracer(trace));
+ }
+
+ static promiseify<T, L extends ITraceableLogger<L>, U>(
+ mapper: ITraceableMapper<T, L, U>,
+ ): ITraceableMapper<Promise<T>, L, Promise<U>> {
+ return (traceablePromise) => traceablePromise.map(
+ async ({ item: promise }) => {
+ const t = await promise;
+ return traceablePromise.map(() => t).map(mapper).item;
+ });
+// return (traceable) =>
+// traceable.item.then((item) => mapper(new TraceableImpl(item, traceable.logger)));
+ }
+
+ static from<T>(t: T) {
+ return new TraceableImpl(t, new TraceableLogger());
+ }
+}
+
+export interface Traceable<T> extends ITraceable<T, TraceableLogger>
diff --git a/utils/validate_identifier.ts b/utils/validate_identifier.ts
index 0c9242c..c204497 100644
--- a/utils/validate_identifier.ts
+++ b/utils/validate_identifier.ts
@@ -1,3 +1,11 @@
export const validateIdentifier = (token: string) => {
return (/^[a-zA-Z0-9_\-:. \/]+$/).test(token) && !token.includes("..");
};
+
+export const invalidExecutionEntriesOf = (
+ obj: Record<string, string>,
+): Array<[string, string]> => {
+ return Object.entries(obj).filter((e) =>
+ !e.every((x) => typeof x === "string" && validateIdentifier(x))
+ );
+};