201 行
6.7 KiB
JavaScript
201 行
6.7 KiB
JavaScript
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
|
|
const {
|
|
AuthConcurrencyCheckError,
|
|
validateAuthConcurrencyEnvironment,
|
|
validateAuthRegressionEnvironment,
|
|
} = require("../../../src/scripts/check-auth-postgres-concurrency");
|
|
|
|
const REPO_ROOT = path.resolve(__dirname, "../../../..");
|
|
|
|
function validEnv() {
|
|
return {
|
|
RUN_AUTH_POSTGRES_CONCURRENCY: "1",
|
|
RUN_AUTH_SECURITY_REGRESSION: "1",
|
|
NODE_ENV: "test",
|
|
RATE_LIMIT_ENABLED: "false",
|
|
DEV_SHOW_PASSWORD_RESET_CODE: "false",
|
|
TRUST_PROXY_HOPS: "0",
|
|
EMAIL_ENABLED: "false",
|
|
SMTP_HOST: "",
|
|
SMTP_USER: "",
|
|
SMTP_PASS: "",
|
|
IM_NOTIFIER_ENABLED: "false",
|
|
WECOM_ENABLED: "false",
|
|
WECOM_AGENT_SECRET: "",
|
|
OIDC_ENABLED: "false",
|
|
OIDC_CLIENT_SECRET: "",
|
|
DATABASE_URL:
|
|
"postgresql://test-user:[email protected]:5432/hyb_oa_auth_test?schema=public",
|
|
AUTH_SECURITY_DATABASE_CONFIRM: "hyb_oa_auth_test",
|
|
BASE_URL: "http://127.0.0.1:3456",
|
|
AUTH_CODE_PEPPER: "test-auth-code-pepper-with-at-least-32-bytes",
|
|
JWT_SECRET: "independent-test-jwt-secret",
|
|
FIELD_ENCRYPTION_KEY: "test-field-encryption-key",
|
|
AUTH_SECURITY_EMPLOYEE_ID: "11111111-1111-4111-8111-111111111111",
|
|
AUTH_SECURITY_EMPLOYEE_EMAIL: "[email protected]",
|
|
AUTH_SECURITY_CURRENT_PASSWORD: "SyntheticPassword1234",
|
|
};
|
|
}
|
|
|
|
function expectSafeFailure(env, expectedCode) {
|
|
try {
|
|
validateAuthConcurrencyEnvironment(env);
|
|
throw new Error("expected validation to fail");
|
|
} catch (error) {
|
|
expect(error).toBeInstanceOf(AuthConcurrencyCheckError);
|
|
expect(error.safeCode).toBe(expectedCode);
|
|
expect(error.message).toBe(expectedCode);
|
|
}
|
|
}
|
|
|
|
describe("auth PostgreSQL concurrency guard", () => {
|
|
it("accepts only an explicitly confirmed isolated loopback target", () => {
|
|
expect(validateAuthConcurrencyEnvironment(validEnv())).toEqual(
|
|
expect.objectContaining({
|
|
baseUrl: "http://127.0.0.1:3456",
|
|
employeeId: "11111111-1111-4111-8111-111111111111",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("does not run without the explicit opt-in", () => {
|
|
expectSafeFailure(
|
|
{ ...validEnv(), RUN_AUTH_POSTGRES_CONCURRENCY: "0" },
|
|
"explicit_opt_in_required",
|
|
);
|
|
});
|
|
|
|
it("validates the base regression target before employee-scoped checks", () => {
|
|
const env = validEnv();
|
|
delete env.AUTH_SECURITY_EMPLOYEE_ID;
|
|
delete env.AUTH_SECURITY_EMPLOYEE_EMAIL;
|
|
delete env.AUTH_SECURITY_CURRENT_PASSWORD;
|
|
|
|
expect(validateAuthRegressionEnvironment(env)).toEqual(
|
|
expect.objectContaining({ baseUrl: "http://127.0.0.1:3456" }),
|
|
);
|
|
expectSafeFailure(
|
|
{ ...env, RUN_AUTH_SECURITY_REGRESSION: "0" },
|
|
"regression_opt_in_required",
|
|
);
|
|
});
|
|
|
|
it("refuses production and enabled rate limiting", () => {
|
|
expectSafeFailure({ ...validEnv(), NODE_ENV: "production" }, "test_environment_required");
|
|
expectSafeFailure(
|
|
{ ...validEnv(), RATE_LIMIT_ENABLED: "true" },
|
|
"rate_limit_must_be_disabled",
|
|
);
|
|
});
|
|
|
|
it("refuses inherited proxy and external notification providers", () => {
|
|
expectSafeFailure(
|
|
{ ...validEnv(), TRUST_PROXY_HOPS: "1" },
|
|
"trust_proxy_must_be_disabled",
|
|
);
|
|
expectSafeFailure(
|
|
{ ...validEnv(), EMAIL_ENABLED: "true" },
|
|
"email_provider_must_be_disabled",
|
|
);
|
|
expectSafeFailure(
|
|
{ ...validEnv(), SMTP_HOST: "smtp.example.test" },
|
|
"smtp_host_forbidden",
|
|
);
|
|
expectSafeFailure(
|
|
{ ...validEnv(), IM_NOTIFIER_ENABLED: "true" },
|
|
"im_notifier_must_be_disabled",
|
|
);
|
|
expectSafeFailure(
|
|
{ ...validEnv(), OIDC_ENABLED: "true" },
|
|
"oidc_must_be_disabled",
|
|
);
|
|
});
|
|
|
|
it("refuses remote PostgreSQL authority and query-host overrides", () => {
|
|
expectSafeFailure(
|
|
{
|
|
...validEnv(),
|
|
DATABASE_URL:
|
|
"postgresql://test-user:[email protected]:5432/hyb_oa_auth_test",
|
|
},
|
|
"database_host_not_loopback",
|
|
);
|
|
expectSafeFailure(
|
|
{
|
|
...validEnv(),
|
|
DATABASE_URL:
|
|
"postgresql://test-user:[email protected]:5432/hyb_oa_auth_test?host=db.internal",
|
|
},
|
|
"database_host_not_loopback",
|
|
);
|
|
});
|
|
|
|
it("refuses non-isolated or unconfirmed database names", () => {
|
|
expectSafeFailure(
|
|
{
|
|
...validEnv(),
|
|
DATABASE_URL: "postgresql://test-user:[email protected]:5432/hyb_oa_dev",
|
|
AUTH_SECURITY_DATABASE_CONFIRM: "hyb_oa_dev",
|
|
},
|
|
"database_name_not_isolated",
|
|
);
|
|
expectSafeFailure(
|
|
{ ...validEnv(), AUTH_SECURITY_DATABASE_CONFIRM: "hyb_oa_auth_other" },
|
|
"database_confirmation_mismatch",
|
|
);
|
|
});
|
|
|
|
it("refuses a remote API or enabled code logging", () => {
|
|
expectSafeFailure(
|
|
{ ...validEnv(), BASE_URL: "https://oa.example.test" },
|
|
"base_url_not_loopback",
|
|
);
|
|
expectSafeFailure(
|
|
{ ...validEnv(), DEV_SHOW_PASSWORD_RESET_CODE: "true" },
|
|
"code_logging_forbidden",
|
|
);
|
|
});
|
|
|
|
it("keeps the HTTP regression fail-closed and redacted", () => {
|
|
const source = fs.readFileSync(
|
|
path.join(REPO_ROOT, "server/scripts/regression-auth-security.sh"),
|
|
"utf8",
|
|
);
|
|
const guardIndex = source.indexOf("validateAuthRegressionEnvironment");
|
|
const firstApiWriteIndex = source.indexOf("$BASE_URL/api/auth/login");
|
|
|
|
expect(guardIndex).toBeGreaterThan(-1);
|
|
expect(firstApiWriteIndex).toBeGreaterThan(guardIndex);
|
|
expect(source).not.toMatch(/cat\s+[^\n]*body/i);
|
|
expect(source).toContain("[AUTH-REGRESSION][PARTIAL] BASE_ONLY");
|
|
expect(source).toContain("[AUTH-REGRESSION][PASS] FULL");
|
|
expect(source).toContain("invalid_concurrency_mode");
|
|
});
|
|
|
|
it("keeps auth-security-local isolated and cleanup failures authoritative", () => {
|
|
const source = fs.readFileSync(
|
|
path.join(REPO_ROOT, "scripts/qa/run-web-gates.sh"),
|
|
"utf8",
|
|
);
|
|
const dropFunction = source.slice(
|
|
source.indexOf("qa_dropdb()"),
|
|
source.indexOf("qa_cleanup_server()"),
|
|
);
|
|
|
|
expect(source).toContain("hyb-oa-web-gates-server-${QA_RUN_ID}.pid");
|
|
expect(source).toContain('QA_SERVER_STARTED=0');
|
|
expect(source).toContain('QA_SERVER_OWNED=0');
|
|
expect(source).toContain('export TRUST_PROXY_HOPS=0');
|
|
expect(source).toContain('export EMAIL_ENABLED=false');
|
|
expect(source).toContain('export OIDC_ENABLED=false');
|
|
expect(source).toContain('unset JWT_SECRET AUTH_CODE_PEPPER FIELD_ENCRYPTION_KEY');
|
|
expect(source).toContain('QA_SERVER_ENTRY="src/scripts/start-auth-security-test-server.js"');
|
|
expect(source).toContain('RUN_AUTH_POSTGRES_CONCURRENCY=1 ./scripts/regression-auth-security.sh');
|
|
expect(source).toContain('exit "$cleanup_status"');
|
|
expect(dropFunction).not.toContain("|| true");
|
|
expect(dropFunction).toContain("return 1");
|
|
});
|
|
});
|