Skip to content

Commit

Permalink
feat(cli): save secrets in single file
Browse files Browse the repository at this point in the history
  • Loading branch information
juanrgm committed Nov 21, 2023
1 parent d764d46 commit cf18e38
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/curly-socks-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rtpl/cli": minor
---

Save secrets in single file
2 changes: 1 addition & 1 deletion packages/cli/src/actions/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type DiffOptions = GlobalOptions & {
};
export default async function diff(options: DiffOptions) {
const tpl = await readTplFile(options.templatePath);
const resources = await resolveTpl(tpl, {
const { resources } = await resolveTpl(tpl, {
filter: options.filter,
lockPath: options.lockPath,
outPath: options.outPath,
Expand Down
8 changes: 6 additions & 2 deletions packages/cli/src/actions/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { readTplFile, resolveTpl } from "../utils/self/resolve.js";
import backup from "./backup.js";
import diff from "./diff.js";
import chalk from "chalk";
import { rmdir } from "fs/promises";
import { rmdir, writeFile } from "fs/promises";
import { dirname, join } from "path";

export type InstallActionOptions = GlobalOptions & {
Expand Down Expand Up @@ -49,12 +49,16 @@ export default async function install(options: InstallActionOptions) {
}

const tpl = await readTplFile(options.templatePath);
const resources = await resolveTpl(tpl, {
const { resources, secrets } = await resolveTpl(tpl, {
filter: options.filter,
lockPath: options.lockPath,
outPath: options.outPath,
});

const secretsPath = join(dirname(options.lockPath), "rtpl.secrets.json");

await writeFile(secretsPath, JSON.stringify(secrets, null, 2));

//await tpl.onBeforeInstall?.(options);

const lockData = lock.parseFile(options.lockPath, true) ?? {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/actions/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { readTplFile, resolveTpl } from "../utils/self/resolve.js";

export default async function render(options: GlobalOptions) {
const tpl = await readTplFile(options.templatePath);
const resources = await resolveTpl(tpl, {
const { resources } = await resolveTpl(tpl, {
filter: options.filter,
lockPath: options.lockPath,
outPath: options.outPath,
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ export { MinimalTpl, MinimalTplConfig } from "./utils/self/tpl.js";
export {
AbstractRes,
type ResOptions,
type MinimalRes,
ResType,
} from "./resources/AbstractRes.js";
export { CronRes, CronData } from "./resources/CronRes.js";
export { DirRes, DirData } from "./resources/DirRes.js";
export { DirRes, DirData, type MinimalDirRes } from "./resources/DirRes.js";
export { EnvRes, EnvData } from "./resources/EnvRes.js";
export { IniRes, IniData } from "./resources/IniRes.js";
export { JsonRes } from "./resources/JsonRes.js";
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/resources/AbstractRes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Secrets } from "../utils/self/secrets.js";
import { Call, getLastStacks } from "../utils/stack.js";
import { DelayedValue, setDelayedValue } from "./DelayedValue.js";
import { posix } from "path";
Expand Down Expand Up @@ -88,7 +89,7 @@ export abstract class AbstractRes<
);
}

async onReady(path: string) {
async onReady(path: string, secrets: Secrets) {
setDelayedValue(this.path, path);
setDelayedValue(this.dirname, path);
}
Expand Down
12 changes: 6 additions & 6 deletions packages/cli/src/resources/SecretRes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
randomString,
upperAlphaCharset,
} from "../utils/crypto.js";
import { readIfExists } from "../utils/fs.js";
import { Secrets } from "../utils/self/secrets.js";
import { AbstractRes, ResOptions, ResType } from "./AbstractRes.js";
import { DelayedValue, setDelayedValue } from "./DelayedValue.js";

Expand Down Expand Up @@ -46,7 +46,7 @@ export class SecretRes extends AbstractRes<
protected override readonly type = ResType.Secret;
private value: DelayedValue<string>;
readonly hasNewValue: DelayedValue<boolean>;
constructor(readonly options: ResOptions<SecretData>) {
constructor(readonly options: ResOptions<SecretData | undefined>) {
super(options);
this.value = new DelayedValue(undefined, this.lastStacks);
this.hasNewValue = new DelayedValue(undefined, this.lastStacks);
Expand All @@ -60,9 +60,9 @@ export class SecretRes extends AbstractRes<
override toString() {
return this.value.toString();
}
override async onReady(path: string) {
await super.onReady(path);
const value = (await readIfExists(path))?.toString();
override async onReady(path: string, secrets: Secrets) {
await super.onReady(path, secrets);
const value = secrets[path];
const hasNewValue = value ? false : true;
const generate = this.data?.generate ?? true;
let endValue = value;
Expand All @@ -83,7 +83,7 @@ export class SecretRes extends AbstractRes<
if (charset.length <= 10) {
throw new Error(`Charset length is too small`);
}
endValue = randomString(length, charset);
endValue = secrets[path] = randomString(length, charset);
}
const auxValue = await this.data?.onReady?.({
path,
Expand Down
7 changes: 5 additions & 2 deletions packages/cli/src/utils/self/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { isPlainObject } from "../object.js";
import { isDir, isPath, stripRootBackPaths } from "../path.js";
import { makeFilter } from "../string.js";
import { createResourceSystem } from "./rs.js";
import { getSecretsPath, parseSecretsFile } from "./secrets.js";
import { MinimalTpl, ResourcesResultItem } from "./tpl.js";
import mm from "micromatch";
import { basename, dirname, join, relative } from "path";
Expand Down Expand Up @@ -194,11 +195,13 @@ export async function resolveTpl(
await item.tpl.config.onResolve?.bind(rs)(item.resources, tplOptions);
}

const secretsPath = getSecretsPath(lockDir);
const secrets = await parseSecretsFile(secretsPath);
const resources = await resolveResources({
...resolveOptions,
resources: inResources,
onValue: async (path, res, actions) => {
await res.onReady(posix.join(outFolder, path));
await res.onReady(posix.join(outFolder, path), secrets);
if (MinimalDirRes.isInstance(res)) {
actions.add = false;
actions.process = !res.resolved;
Expand All @@ -218,5 +221,5 @@ export async function resolveTpl(
delete resources[path];
}

return resources;
return { resources, secrets };
}
13 changes: 13 additions & 0 deletions packages/cli/src/utils/self/secrets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { readIfExists } from "../fs.js";
import { join } from "path";

export type Secrets = Record<string /* path */, string>;

export function getSecretsPath(dir: string) {
return join(dir, "rtpl.secrets.json");
}

export async function parseSecretsFile(path: string): Promise<Secrets> {
const buffer = await readIfExists(path);
return buffer ? JSON.parse(buffer.toString()) : {};
}

0 comments on commit cf18e38

Please sign in to comment.