New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

embedded-postgres

Package Overview
Dependencies
Maintainers
1
Versions
121
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

embedded-postgres - npm Package Compare versions

Comparing version 11.20.0-beta.8 to 11.20.0-beta.9

dist/embedded-postgres.d.ts

34

dist/index.d.ts

@@ -5,5 +5,5 @@ import { Client } from 'pg';

*/
interface PostgresOptions {
export interface PostgresOptions {
/** The location where the data should be persisted to. Defaults to: `./data/db` */
database_dir: string;
databaseDir: string;
/** The port where the Postgres database should be listening. Defaults to:

@@ -18,6 +18,25 @@ * `5432` */

* Defaults to `password` */
auth_method: 'scram-sha-256' | 'password' | 'md5';
authMethod: 'scram-sha-256' | 'password' | 'md5';
/** Whether all data should be left in place when the database is shut down.
* Defaults to true. */
persistent: boolean;
/** Pass any additional flags to the initdb process. You can find all
* available flags here:
* https://www.postgresql.org/docs/current/app-initdb.html. Flags should be
* passed as a string array, e.g. `["--debug"]` or `["--locale=en-GB"]` */
initdbFlags: string[];
/** Pass any additional flags to the postgres process. You can find all
* available flags here:
* https://www.postgresql.org/docs/current/app-postgres.html. Flags should
* be passed as a string array, e.g. `["--debug"]` or `["--locale=en-GB"]` */
postgresFlags: string[];
/**
* Postgres does not allow binaries to be run by root. In case you're
* running in root-only enviroments, such as Docker containers, you may need
* to create an extra user on your system in order to be able to call the binaries.
*
* NOTE: This WILL irreversibly modify your host system. The effects are
* somewhat minor, but it's still recommend to only use this in Docker containers.
*/
createPostgresUser: boolean;
}

@@ -32,2 +51,3 @@ /**

private process?;
private isRootUser;
constructor(options?: Partial<PostgresOptions>);

@@ -70,3 +90,11 @@ /**

dropDatabase(name: string): Promise<void>;
/**
* Warn the user in case they're trying to run this library as a root user
*/
private checkForRootUser;
/**
* Retrieve the uid and gid for a particular user
*/
private getUidAndGid;
}
export = EmbeddedPostgres;

@@ -5,19 +5,22 @@ "use strict";

};
const child_process_1 = require("child_process");
const path_1 = __importDefault(require("path"));
const crypto_1 = __importDefault(require("crypto"));
const promises_1 = __importDefault(require("fs/promises"));
const os_1 = require("os");
const crypto_1 = __importDefault(require("crypto"));
const child_process_1 = require("child_process");
const pg_1 = require("pg");
const async_exit_hook_1 = __importDefault(require("async-exit-hook"));
const binary_1 = __importDefault(require("./binary"));
const async_exit_hook_1 = __importDefault(require("async-exit-hook"));
const { postgres, initdb } = (0, binary_1.default)();
// The default configuration options for the class
const defaults = {
database_dir: path_1.default.join(process.cwd(), 'data', 'db'),
databaseDir: path_1.default.join(process.cwd(), 'data', 'db'),
port: 5432,
user: 'postgres',
password: 'password',
auth_method: 'password',
authMethod: 'password',
persistent: true,
initdbFlags: [],
postgresFlags: [],
createPostgresUser: false,
};

@@ -36,5 +39,15 @@ /**

constructor(options = {}) {
// Options were previously specified in snake_case rather than
// camelCase. We still want to accept the old style of options.
const legacyOptions = {};
if (options.database_dir) {
legacyOptions.databaseDir = options.database_dir;
}
if (options.auth_method) {
legacyOptions.authMethod = options.auth_method;
}
// Assign default options to options object
this.options = Object.assign({}, defaults, options);
this.options = Object.assign({}, defaults, legacyOptions, options);
instances.add(this);
this.isRootUser = (0, os_1.userInfo)().uid === 0;
}

@@ -48,2 +61,33 @@ /**

async initialise() {
// GUARD: Check that a postgres user is available
await this.checkForRootUser();
// Optionally retrieve the uid and gid
let permissionIds = await this.getUidAndGid()
.catch(() => ({}));
// GUARD: Check if we need to create users
if (this.options.createPostgresUser
&& !('uid' in permissionIds)
&& !('gid' in permissionIds)) {
try {
// Create the group and user
await execAsync('groupadd postgres');
await execAsync('useradd -g postgres postgres');
// Re-treieve the permission ids now the user exists
permissionIds = await this.getUidAndGid();
}
catch (err) {
console.error(err);
throw new Error('Failed to create and initialize a new user on this system.');
}
}
// GUARD: Ensure that the data directory is owned by the created user
if (this.options.createPostgresUser) {
if (!('uid' in permissionIds)) {
throw new Error('Failed to retrieve the uid for the newly created user.');
}
// Create the data directory and have the user own it, so we
// don't get any permission errors
await promises_1.default.mkdir(this.options.databaseDir, { recursive: true });
await promises_1.default.chown(this.options.databaseDir, permissionIds.uid, permissionIds.gid);
}
// Create a file on disk that contains the password in plaintext

@@ -59,7 +103,8 @@ const randomId = crypto_1.default.randomBytes(6).readUIntLE(0, 6).toString(36);

const process = (0, child_process_1.spawn)(initdb, [
`--pgdata=${this.options.database_dir}`,
`--auth=${this.options.auth_method}`,
`--pgdata=${this.options.databaseDir}`,
`--auth=${this.options.authMethod}`,
`--username=${this.options.user}`,
`--pwfile=${passwordFile}`,
], { stdio: 'inherit' });
...this.options.initdbFlags,
], { stdio: 'inherit', ...permissionIds });
process.on('exit', (code) => {

@@ -83,2 +128,7 @@ if (code === 0) {

async start() {
// Optionally retrieve the uid and gid
const permissionIds = await this.getUidAndGid()
.catch(() => {
throw new Error('Postgres cannot run as a root user. embedded-postgres could not find a postgres user to run as instead. Consider using the `createPostgresUser` option.');
});
// Greedily make the file executable, in case it is not

@@ -91,6 +141,7 @@ await promises_1.default.chmod(postgres, '755');

'-D',
this.options.database_dir,
this.options.databaseDir,
'-p',
this.options.port.toString(),
]);
...this.options.postgresFlags,
], { ...permissionIds });
// Connect to stderr, as that is where the messages get sent

@@ -132,3 +183,3 @@ (_a = this.process.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (chunk) => {

// Delete the data directory
await promises_1.default.rm(this.options.database_dir, { recursive: true, force: true });
await promises_1.default.rm(this.options.databaseDir, { recursive: true, force: true });
}

@@ -187,4 +238,53 @@ }

}
/**
* Warn the user in case they're trying to run this library as a root user
*/
async checkForRootUser() {
// GUARD: Ensure that the user isn't root
if (!this.isRootUser) {
return;
}
// Attempt to retrieve the uid and gid for the postgres user. This check
// will throw and error when the postgres user doesn't exist
try {
await this.getUidAndGid();
}
catch (err) {
// GUARD: No user exists, but check that a postgres user should be created
if (!this.options.createPostgresUser) {
throw new Error('You are running this script as root. Postgres does not support running as root. If you wish to continue, configure embedded-postgres to create a Postgres user by setting the `createPostgresUser` option to true.');
}
}
}
/**
* Retrieve the uid and gid for a particular user
*/
async getUidAndGid(name = 'postgres') {
if (!this.isRootUser) {
return {};
}
const [uid, gid] = await Promise.all([
execAsync(`id -u ${name}`).then(Number.parseInt),
execAsync(`id -g ${name}`).then(Number.parseInt),
]);
return { uid, gid };
}
}
/**
* A promisified version of the exec API that either throws on errors or returns
* the string results from the executed command.
*/
async function execAsync(command) {
return new Promise((resolve, reject) => {
(0, child_process_1.exec)(command, (error, stdout) => {
if (error) {
reject(error);
}
else {
resolve(stdout);
}
});
});
}
/**
* This script should be called when a Node script is exited, so that we can

@@ -191,0 +291,0 @@ * nicely shutdown all potentially started clusters, and we don't end up with

25

package.json
{
"name": "embedded-postgres",
"version": "11.20.0-beta.8",
"version": "11.20.0-beta.9",
"description": "A package to run an embedded Postgresql database right from NodeJS",

@@ -9,3 +9,4 @@ "main": "./dist/index.js",

"build": "tsc",
"lint": "eslint ./src --ext ts"
"lint": "eslint ./src --ext ts",
"docs": "typedoc --plugin typedoc-plugin-markdown ./src/types.ts --theme markdown --excludePrivate"
},

@@ -21,3 +22,3 @@ "keywords": [

"devDependencies": {
"@embedded-postgres/symlink-reader": "^11.20.0-beta.8",
"@embedded-postgres/symlink-reader": "^11.20.0-beta.9",
"@types/async-exit-hook": "^2.0.0",

@@ -29,10 +30,10 @@ "@types/pg": "^8.6.5",

"optionalDependencies": {
"@embedded-postgres/darwin-arm64": "^11.20.0-beta.8",
"@embedded-postgres/darwin-x64": "^11.20.0-beta.8",
"@embedded-postgres/linux-arm": "^11.20.0-beta.8",
"@embedded-postgres/linux-arm64": "^11.20.0-beta.8",
"@embedded-postgres/linux-ia32": "^11.20.0-beta.8",
"@embedded-postgres/linux-ppc64": "^11.20.0-beta.8",
"@embedded-postgres/linux-x64": "^11.20.0-beta.8",
"@embedded-postgres/windows-x64": "^11.20.0-beta.8"
"@embedded-postgres/darwin-arm64": "^11.20.0-beta.9",
"@embedded-postgres/darwin-x64": "^11.20.0-beta.9",
"@embedded-postgres/linux-arm": "^11.20.0-beta.9",
"@embedded-postgres/linux-arm64": "^11.20.0-beta.9",
"@embedded-postgres/linux-ia32": "^11.20.0-beta.9",
"@embedded-postgres/linux-ppc64": "^11.20.0-beta.9",
"@embedded-postgres/linux-x64": "^11.20.0-beta.9",
"@embedded-postgres/windows-x64": "^11.20.0-beta.9"
},

@@ -50,3 +51,3 @@ "dependencies": {

],
"gitHead": "34632a4940769ac5ce0c2b1e94add4cf73715452"
"gitHead": "85d7084328cdde8feed11e7c27c31915f19ce550"
}

@@ -15,3 +15,3 @@ # embedded-postgres

const pg = new EmbeddedPostgres({
data_dir: './data/db',
databaseDir: './data/db',
user: 'postgres',

@@ -18,0 +18,0 @@ password: 'password',

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc