Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/add-public-decorator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"varlock": patch
---

Add `@public` item decorator as the counterpart to `@sensitive`, matching the pattern of `@required`/`@optional` decorator pairs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ SERVICE_X_CLIENT_ID=
```
</div>

<div>
### `@public`
**Value type:** `boolean`

Opposite of [`@sensitive`](#sensitive). Equivalent to writing `@sensitive=false`.

```env-spec
# @defaultSensitive=true
# ---
# @public
PUBLIC_API_URL=https://api.example.com
```
</div>

<div>
### `@type`
**Value type:** [`data type`](/reference/data-types) (name only or function call)
Expand Down
13 changes: 9 additions & 4 deletions packages/varlock/src/env-graph/lib/config-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,21 +336,26 @@ export class ConfigItem {
private async processSensitive() {
const sensitiveFromDataType = this.dataType?.isSensitive;
for (const def of this.defs) {
const sensitiveDec = def.itemDef.decorators?.find((d) => d.name === 'sensitive');
const sensitiveDecs = def.itemDef.decorators?.filter((d) => d.name === 'sensitive' || d.name === 'public') || [];
// NOTE - checks for duplicates and using sensitive+public together are already handled more generally
const sensitiveDec = sensitiveDecs[0];

// Explicit per-item decorators
if (sensitiveDec) {
const usingPublic = sensitiveDec.name === 'public';

const sensitiveDecValue = await sensitiveDec.resolve();
// can bail if the decorator value resolution failed
if (sensitiveDec.schemaErrors.length) {
return;
}
if (![true, false, undefined].includes(sensitiveDecValue)) {
throw new SchemaError('@sensitive must resolve to a boolean or undefined');
throw new SchemaError('@sensitive/@public must resolve to a boolean or undefined');
}
if (sensitiveDecValue !== undefined) {
this._isSensitive = sensitiveDecValue;
this._isSensitive = usingPublic ? !sensitiveDecValue : sensitiveDecValue;
return;
}
// TODO: do we want an opposite decorator similar to @required/@optional -- maybe @public?
}

// we skip `defaultSensitive` behaviour if the data type specifies sensitivity
Expand Down
4 changes: 4 additions & 0 deletions packages/varlock/src/env-graph/lib/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ export const builtInItemDecorators: Array<ItemDecoratorDef<any>> = [
{
name: 'sensitive',
},
{
name: 'public',
incompatibleWith: ['sensitive'],
},
{
name: 'type',
useFnArgsResolver: true,
Expand Down
50 changes: 50 additions & 0 deletions packages/varlock/src/env-graph/test/sensitive-decorator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,45 @@ describe('@sensitive and @defaultSensitive tests', () => {
},
}));

test('@public and @sensitive mark items properly', envFilesTest({
envFile: outdent`
SENSITIVE= # @sensitive
SENSITIVE_TRUE= # @sensitive=true
SENSITIVE_FALSE= # @sensitive=false
SENSITIVE_UNDEF= # @sensitive=undefined
PUBLIC= # @public
PUBLIC_TRUE= # @public=true
PUBLIC_FALSE= # @public=false
PUBLIC_UNDEF= # @public=undefined
`,
expectSensitive: {
SENSITIVE: true,
SENSITIVE_TRUE: true,
SENSITIVE_FALSE: false,
SENSITIVE_UNDEF: true, // stays as default
PUBLIC: false,
PUBLIC_TRUE: false,
PUBLIC_FALSE: true,
PUBLIC_UNDEF: true, // stays as default
},
}));

test('@public and @sensitive can be overridden', envFilesTest({
files: {
'.env.schema': outdent`
WAS_SENSITIVE= # @sensitive
WAS_PUBLIC= # @public
`,
'.env': outdent`
WAS_SENSITIVE= # @public
WAS_PUBLIC= # @sensitive
`,
},
expectSensitive: {
WAS_SENSITIVE: false, WAS_PUBLIC: true,
},
}));

describe('dynamic @sensitive', () => {
test('dynamic @sensitive works', envFilesTest({
envFile: outdent`
Expand All @@ -54,6 +93,17 @@ describe('@sensitive and @defaultSensitive tests', () => {
TRUE: true, FALSE: false, UNDEF: true,
},
}));

test('dynamic @public works', envFilesTest({
envFile: outdent`
TRUE= # @public=if(yes)
FALSE= # @public=if(0)
UNDEF= # @public=if(true, undefined) # uses default
`,
expectSensitive: {
TRUE: false, FALSE: true, UNDEF: true,
},
}));
});

describe('inferFromPrefix() - use key prefix to infer sensitivity', () => {
Expand Down