mirror of
https://github.com/denoland/std.git
synced 2024-11-22 04:59:05 +00:00
feat(dotenv): allow reading from .env
files without granting env access (#3306)
This commit is contained in:
parent
0f28d392e3
commit
29e2dc51e1
@ -178,7 +178,7 @@ const RE_ExpandValue =
|
||||
|
||||
export function parse(
|
||||
rawDotenv: string,
|
||||
restrictEnvAccessTo: StringList = [],
|
||||
restrictEnvAccessTo?: StringList,
|
||||
): Record<string, string> {
|
||||
const env: Record<string, string> = {};
|
||||
|
||||
@ -224,7 +224,7 @@ export function loadSync(
|
||||
defaultsPath = ".env.defaults",
|
||||
export: _export = false,
|
||||
allowEmptyValues = false,
|
||||
restrictEnvAccessTo = [],
|
||||
restrictEnvAccessTo,
|
||||
}: LoadOptions = {},
|
||||
): Record<string, string> {
|
||||
const conf = envPath ? parseFileSync(envPath, restrictEnvAccessTo) : {};
|
||||
@ -268,7 +268,7 @@ export async function load(
|
||||
defaultsPath = ".env.defaults",
|
||||
export: _export = false,
|
||||
allowEmptyValues = false,
|
||||
restrictEnvAccessTo = [],
|
||||
restrictEnvAccessTo,
|
||||
}: LoadOptions = {},
|
||||
): Promise<Record<string, string>> {
|
||||
const conf = envPath ? await parseFile(envPath, restrictEnvAccessTo) : {};
|
||||
@ -305,7 +305,7 @@ export async function load(
|
||||
|
||||
function parseFileSync(
|
||||
filepath: string,
|
||||
restrictEnvAccessTo: StringList = [],
|
||||
restrictEnvAccessTo?: StringList,
|
||||
): Record<string, string> {
|
||||
try {
|
||||
return parse(Deno.readTextFileSync(filepath), restrictEnvAccessTo);
|
||||
@ -317,7 +317,7 @@ function parseFileSync(
|
||||
|
||||
async function parseFile(
|
||||
filepath: string,
|
||||
restrictEnvAccessTo: StringList = [],
|
||||
restrictEnvAccessTo?: StringList,
|
||||
): Promise<Record<string, string>> {
|
||||
try {
|
||||
return parse(await Deno.readTextFile(filepath), restrictEnvAccessTo);
|
||||
@ -344,7 +344,7 @@ function assertSafe(
|
||||
conf: Record<string, string>,
|
||||
confExample: Record<string, string>,
|
||||
allowEmptyValues: boolean,
|
||||
restrictEnvAccessTo: StringList = [],
|
||||
restrictEnvAccessTo?: StringList,
|
||||
) {
|
||||
const currentEnv = readEnv(restrictEnvAccessTo);
|
||||
|
||||
@ -381,10 +381,7 @@ function assertSafe(
|
||||
// a guarded env access, that reads only a subset from the Deno.env object,
|
||||
// if `restrictEnvAccessTo` property is passed.
|
||||
function readEnv(restrictEnvAccessTo: StringList) {
|
||||
if (
|
||||
restrictEnvAccessTo && Array.isArray(restrictEnvAccessTo) &&
|
||||
restrictEnvAccessTo.length > 0
|
||||
) {
|
||||
if (restrictEnvAccessTo && Array.isArray(restrictEnvAccessTo)) {
|
||||
return restrictEnvAccessTo.reduce(
|
||||
(
|
||||
accessedEnvVars: Record<string, string>,
|
||||
|
@ -581,6 +581,7 @@ Deno.test("expand variables", () => {
|
||||
"variables within and without brackets expanded",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("stringify", async (t) => {
|
||||
await t.step(
|
||||
"basic",
|
||||
@ -758,7 +759,7 @@ Deno.test("type inference based on restrictEnvAccessTo", async (t) => {
|
||||
});
|
||||
|
||||
Deno.test(
|
||||
"prevent file systems reads of default path parameter values by using explicit null",
|
||||
"prevent file system reads of default path parameter values by using explicit null",
|
||||
{
|
||||
permissions: {
|
||||
env: ["GREETING", "DO_NOT_OVERRIDE"],
|
||||
@ -785,13 +786,15 @@ Deno.test(
|
||||
examplePath: null,
|
||||
} satisfies LoadOptions;
|
||||
|
||||
await t.step("load", async () => {
|
||||
assertStrictEquals(Object.keys(await load(optsNoPaths)).length, 0);
|
||||
|
||||
const env = await load(optsOnlyEnvPath);
|
||||
const assertEnv = (env: Record<string, string>): void => {
|
||||
assertStrictEquals(Object.keys(env).length, 2);
|
||||
assertStrictEquals(env["GREETING"], "hello world");
|
||||
assertStrictEquals(env["DO_NOT_OVERRIDE"], "overridden");
|
||||
};
|
||||
|
||||
await t.step("load", async () => {
|
||||
assertStrictEquals(Object.keys(await load(optsNoPaths)).length, 0);
|
||||
assertEnv(await load(optsOnlyEnvPath));
|
||||
|
||||
assertRejects(
|
||||
() => load(optsEnvPath),
|
||||
@ -814,11 +817,7 @@ Deno.test(
|
||||
|
||||
await t.step("loadSync", () => {
|
||||
assertStrictEquals(Object.keys(loadSync(optsNoPaths)).length, 0);
|
||||
|
||||
const env = loadSync(optsOnlyEnvPath);
|
||||
assertStrictEquals(Object.keys(env).length, 2);
|
||||
assertStrictEquals(env["GREETING"], "hello world");
|
||||
assertStrictEquals(env["DO_NOT_OVERRIDE"], "overridden");
|
||||
assertEnv(loadSync(optsOnlyEnvPath));
|
||||
|
||||
assertThrows(
|
||||
() => loadSync(optsEnvPath),
|
||||
@ -840,3 +839,44 @@ Deno.test(
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
Deno.test(
|
||||
"use restrictEnvAccessTo with empty array to prevent env access and read only from fs",
|
||||
{ permissions: { read: [testOptions.envPath] } },
|
||||
async (t) => {
|
||||
const optsOnlyEnvPath = {
|
||||
envPath: testOptions.envPath,
|
||||
defaultsPath: null,
|
||||
examplePath: null,
|
||||
} satisfies LoadOptions;
|
||||
|
||||
const optsNoEnvAccess = {
|
||||
...optsOnlyEnvPath,
|
||||
restrictEnvAccessTo: [],
|
||||
} satisfies LoadOptions;
|
||||
|
||||
const assertEnv = (env: Record<string, string>): void => {
|
||||
assertStrictEquals(Object.keys(env).length, 2);
|
||||
assertStrictEquals(env["GREETING"], "hello world");
|
||||
assertStrictEquals(env["DO_NOT_OVERRIDE"], "overridden");
|
||||
};
|
||||
|
||||
await t.step("load", async () => {
|
||||
assertEnv(await load(optsNoEnvAccess));
|
||||
assertRejects(
|
||||
() => load(optsOnlyEnvPath),
|
||||
Deno.errors.PermissionDenied,
|
||||
`Requires env access to all, run again with the --allow-env flag`,
|
||||
);
|
||||
});
|
||||
|
||||
await t.step("loadSync", () => {
|
||||
assertEnv(loadSync(optsNoEnvAccess));
|
||||
assertThrows(
|
||||
() => loadSync(optsOnlyEnvPath),
|
||||
Deno.errors.PermissionDenied,
|
||||
`Requires env access to all, run again with the --allow-env flag`,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user