Skip to content

Commit

Permalink
fixup! WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzatron committed Mar 25, 2024
1 parent b566f20 commit 2982ee0
Show file tree
Hide file tree
Showing 11 changed files with 699 additions and 3 deletions.
152 changes: 152 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,23 @@ export const sessionKey = binary("SESSION_KEY", "session token signing key", {
},
],
});

// constraints
export const sessionKey = binary("SESSION_KEY", "session token signing key", {
constraints: [
{
description: "must be 128 or 256 bits",
constrain: (v) =>
[16, 32].includes(v.length) || "decoded length must be 16 or 32",
},
],
examples: [
{
value: Buffer.from("SUPER_SECRET_256_BIT_SIGNING_KEY", "utf-8"),
label: "256-bit key",
},
],
});
```

### `boolean`
Expand Down Expand Up @@ -243,6 +260,24 @@ export const isDebug = boolean(
],
},
);

// constraints
export const isDebug = boolean(
"DEBUG",
"enable or disable debugging features",
{
constraints: [
{
description: "must not be enabled on Windows",
constrain: (v) =>
!v ||
process.platform !== "win32" ||
"must not be enabled on Windows",
},
],
examples: [{ value: false, label: "disabled" }],
},
);
```

### `duration`
Expand Down Expand Up @@ -284,6 +319,23 @@ export const grpcTimeout = duration("GRPC_TIMEOUT", "gRPC request timeout", {
},
],
});

// constraints
export const grpcTimeout = duration("GRPC_TIMEOUT", "gRPC request timeout", {
constraints: [
{
description: "must be a multiple of 100 milliseconds",
constrain: (v) =>
v.milliseconds % 100 === 0 || "must be a multiple of 100 milliseconds",
},
],
examples: [
{
value: Temporal.Duration.from({ milliseconds: 100 }),
label: "100 milliseconds",
},
],
});
```

### `enumeration`
Expand Down Expand Up @@ -343,6 +395,27 @@ export const logLevel = enumeration(
],
},
);

// constraints
export const logLevel = enumeration(
"LOG_LEVEL",
"the minimum log level to record",
members,
{
constraints: [
{
description: "must not be debug on Windows",
constrain: (v) =>
v !== "debug" ||
process.platform !== "win32" ||
"must not be debug on Windows",
},
],
examples: [
{ value: "error", label: "if you only want to see when things go wrong" },
],
},
);
```

### `integer`
Expand Down Expand Up @@ -376,6 +449,17 @@ export const weight = integer("WEIGHT", "weighting for this node", {
{ value: 1000, as: "1e3", label: "highest weight" },
],
});

// constraints
export const weight = integer("WEIGHT", "weighting for this node", {
constraints: [
{
description: "must be a multiple of 10",
constrain: (v) => v % 10 === 0 || "must be a multiple of 10",
},
],
examples: [{ value: 100, label: "100" }],
});
```

### `kubernetesAddress`
Expand Down Expand Up @@ -454,6 +538,21 @@ export const port = networkPortNumber(
],
},
);

// constraints
export const port = networkPortNumber(
"PORT",
"listen port for the HTTP server",
{
constraints: [
{
description: "must not be disallowed",
constrain: (v) => ![1337, 31337].includes(v) || "not allowed",
},
],
examples: [{ value: 8080, label: "standard" }],
},
);
```

### `number`
Expand Down Expand Up @@ -499,6 +598,21 @@ export const sampleRatio = number(
],
},
);

// constraints
export const sampleRatio = number(
"SAMPLE_RATIO",
"ratio of requests to sample",
{
constraints: [
{
description: "must be a multiple of 0.01",
constrain: (v) => v % 0.01 === 0 || "must be a multiple of 0.01",
},
],
examples: [{ value: 0.01, label: "1%" }],
},
);
```

### `string`
Expand Down Expand Up @@ -564,6 +678,27 @@ export const readDsn = string(
],
},
);

// constraints
export const readDsn = string(
"READ_DSN",
"database connection string for read-models",
{
constraints: [
{
description: "must not contain a password",
constrain: (v) =>
!v.includes("password") || "must not contain a password",
},
],
examples: [
{
value: "host=localhost dbname=readmodels user=projector",
label: "local",
},
],
},
);
```

### `url`
Expand Down Expand Up @@ -609,6 +744,23 @@ export const cdnUrl = url("CDN_URL", "CDN to use when serving static assets", {
},
],
});

// constraints
export const cdnUrl = url("CDN_URL", "CDN to use when serving static assets", {
constraints: [
{
description: "must not be a local URL",
constrain: (v) =>
!v.hostname.endsWith(".local") || "must not be a local URL",
},
],
examples: [
{
value: new URL("https://host.example.org/path/to/resource"),
label: "absolute",
},
],
});
```

## See also
Expand Down
2 changes: 1 addition & 1 deletion test/suite/declaration/big-integer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ describe("Big integer declarations", () => {
});
});

describe("when the value violates the constraint", () => {
describe("when the value violates the constraints", () => {
beforeEach(() => {
process.env.EARTH_ATOM_COUNT = "5972200000000000000000001";

Expand Down
59 changes: 59 additions & 0 deletions test/suite/declaration/binary.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,65 @@ describe("Binary declarations", () => {
});
});
});

describe("when the declaration has the constraints from the README", () => {
beforeEach(() => {
declaration = binary("SESSION_KEY", "session token signing key", {
constraints: [
{
description: "must be 128 or 256 bits",
constrain: (v) =>
[16, 32].includes(v.length) || "decoded length must be 16 or 32",
},
],
examples: [
{
value: Buffer.from("SUPER_SECRET_256_BIT_SIGNING_KEY", "utf-8"),
label: "256-bit key",
},
],
});
});

describe("when the value satisfies the constraints", () => {
beforeEach(() => {
process.env.SESSION_KEY = Buffer.from(
"SUPER_SECRET_256_BIT_SIGNING_KEY",
"utf-8",
).toString("base64");

initialize({ onInvalid: noop });
});

describe(".value()", () => {
it("returns the value", () => {
expect(declaration.value().toString("utf-8")).toEqual(
"SUPER_SECRET_256_BIT_SIGNING_KEY",
);
});
});
});

describe("when the value violates the constraints", () => {
beforeEach(() => {
process.env.SESSION_KEY = Buffer.from("INVALID", "utf-8").toString(
"base64",
);

initialize({ onInvalid: noop });
});

describe(".value()", () => {
it("throws", () => {
expect(() => {
declaration.value();
}).toThrow(
"value of SESSION_KEY (SU5WQUxJRA==) is invalid: decoded length must be 16 or 32",
);
});
});
});
});
});

function toEncoding(encoding: BufferEncoding, value: string): string {
Expand Down
75 changes: 74 additions & 1 deletion test/suite/declaration/boolean.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { Declaration } from "../../../src/declaration.js";
import { Options } from "../../../src/declaration/boolean.js";
import { boolean, initialize } from "../../../src/index.js";
Expand Down Expand Up @@ -375,4 +375,77 @@ describe("Boolean declarations", () => {
});
});
});

describe("when the declaration has the constraints from the README", () => {
let realPlatform: NodeJS.Platform;

beforeEach(() => {
declaration = boolean("DEBUG", "enable or disable debugging features", {
constraints: [
{
description: "must not be enabled on Windows",
constrain: (v) =>
!v ||
process.platform !== "win32" ||
"must not be enabled on Windows",
},
],
examples: [{ value: false, label: "disabled" }],
});

realPlatform = process.platform;
});

afterEach(() => {
Object.defineProperty(process, "platform", { value: realPlatform });
});

describe("when the value is false", () => {
beforeEach(() => {
process.env.DEBUG = "false";

initialize({ onInvalid: noop });
});

describe(".value()", () => {
it("returns the value", () => {
expect(declaration.value()).toBe(false);
});
});
});

describe("when the value is true and the platform is not Windows", () => {
beforeEach(() => {
process.env.DEBUG = "true";
Object.defineProperty(process, "platform", { value: "darwin" });

initialize({ onInvalid: noop });
});

describe(".value()", () => {
it("returns the value", () => {
expect(declaration.value()).toBe(true);
});
});
});

describe("when the value is true and the platform is Windows", () => {
beforeEach(() => {
process.env.DEBUG = "true";
Object.defineProperty(process, "platform", { value: "win32" });

initialize({ onInvalid: noop });
});

describe(".value()", () => {
it("throws", () => {
expect(() => {
declaration.value();
}).toThrow(
"value of DEBUG (true) is invalid: must not be enabled on Windows",
);
});
});
});
});
});
Loading

0 comments on commit 2982ee0

Please sign in to comment.