dotsec 2.0.0-alpha.1 → 4.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -105
- package/dist/cli/index.js +120 -20
- package/dist/cli/index.js.map +1 -7
- package/dist/cli/index.mjs +120 -20
- package/dist/cli/index.mjs.map +1 -7
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -7
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -7
- package/package.json +4 -8
- package/src/templates/dotsec.config.ts +1 -13
- package/dist/index.d.ts +0 -148
package/README.md
CHANGED
|
@@ -1,7 +1,45 @@
|
|
|
1
1
|
# dotsec
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
> consider the contents of this file a work in progress, and not yet ready for consumption
|
|
4
|
+
> For now see --help for more information
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
With AWS support:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install dotsec @dotsec/plugin-aws
|
|
12
|
+
npx dotsec --plugin @dotsec/plugin-aws aws init
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
With PKE support:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install dotsec @dotsec/plugin-pke
|
|
19
|
+
npx dotsec --plugin @dotsec/plugin-pke pke init
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npx dotsec --help
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
<!--
|
|
29
|
+
`dotsec` is a tool for managing environment variables in a secure way. Encrypted environment variables are stored in a `.sec` file, and decrypted to a `.env` file. The `.sec` file can be committed to your repository. The `.env` file should not be committed to your repository.
|
|
30
|
+
|
|
31
|
+
Next to encrypting and decrypting environment variables, `dotsec` can also be used to run a command with the values of a `.env` file in its environment, or with the values of a `.sec` file in its environment.
|
|
32
|
+
|
|
33
|
+
As of writing this, `dotsec` supports the following encryption providers:
|
|
34
|
+
|
|
35
|
+
- [AWS Key Management Service (AWS KMS)](https://aws.amazon.com/kms/)
|
|
36
|
+
- [Public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography)
|
|
37
|
+
|
|
38
|
+
When using the AWS plugin, dotsec can also push selected `.env`/`.sec` entries to AWS Systems Manager Parameter Store, and/or AWS Secrets Manager.
|
|
39
|
+
|
|
40
|
+
## Table of Contents
|
|
41
|
+
|
|
42
|
+
- [Installation](#installation)
|
|
5
43
|
|
|
6
44
|
## Features
|
|
7
45
|
|
|
@@ -29,87 +67,7 @@ Encrypts your `.env` file with the AWS Encryption SDK so you can safely commit i
|
|
|
29
67
|
|
|
30
68
|
- For initialisation enough credentials for creating a KMS key, and alias.
|
|
31
69
|
- For usage enough credentials for using the KMS key to encrypt and/or decrypt.
|
|
32
|
-
- An AWS KMS key with an alias.
|
|
33
|
-
|
|
34
|
-
## Installation
|
|
35
|
-
|
|
36
|
-
```sh
|
|
37
|
-
npm install --save-dev dotsec @dotsec/plugin-aws
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Add the folowing to dotsec.config.ts:
|
|
41
|
-
|
|
42
|
-
```ts
|
|
43
|
-
import { DotsecPluginAws } from "@dotsec/plugin-aws";
|
|
44
|
-
import { DotsecConfig } from "dotsec";
|
|
45
|
-
|
|
46
|
-
export const dotsec: DotsecConfig<{ plugins: DotsecPluginAws }> = {
|
|
47
|
-
defaults: {
|
|
48
|
-
encryptionEngine: "aws",
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Usage
|
|
54
|
-
|
|
55
|
-
If you don't have a .env file, create one:
|
|
56
|
-
|
|
57
|
-
```sh
|
|
58
|
-
I_CAN_SEE="clearly now"
|
|
59
|
-
SINGING="in the rain"
|
|
60
|
-
I_BLESS_THE_RAINS="down in Africa"
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Execute a command and use the values of a .env file in its environment
|
|
64
|
-
|
|
65
|
-
```sh
|
|
66
|
-
npx dotsec run --with-env node -e "console.log(process.env.I_BLESS_THE_RAINS)"
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Encrypt a .env file to .sec
|
|
70
|
-
|
|
71
|
-
```sh
|
|
72
|
-
npx dotsec encrypt
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### Execute a command and use the values of a .sec file in its environment
|
|
76
|
-
|
|
77
|
-
```sh
|
|
78
|
-
npx dotsec run --with-sec node -e "console.log(process.env.I_BLESS_THE_RAINS)"
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Decrypt a .sec file to .env
|
|
82
|
-
|
|
83
|
-
```sh
|
|
84
|
-
npx dotsec decrypt
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Push selected .env entries to AWS Systems Manager Parameter Store
|
|
88
|
-
|
|
89
|
-
Edit the `dotsec.config.ts` file. Add the following to the `aws` object:
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
{
|
|
93
|
-
...
|
|
94
|
-
variables: {
|
|
95
|
-
"I_BLESS_THE_RAINS": {
|
|
96
|
-
push: {
|
|
97
|
-
aws: {
|
|
98
|
-
ssm: true
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Run the following command:
|
|
107
|
-
|
|
108
|
-
```sh
|
|
109
|
-
npx dotsec push
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
> You might want to set AWS_REGION before running the command. If you don't, the region will be set to `eu-west-1`.
|
|
70
|
+
- An AWS KMS key with an alias. -->
|
|
113
71
|
<!--
|
|
114
72
|
## Usage
|
|
115
73
|
|
|
@@ -127,15 +85,15 @@ Take not of the `KeyMetadata.KeyId` value, and create an alias for it:
|
|
|
127
85
|
aws kms create-alias --alias-name alias/dotsec --target-key-id <key-id>
|
|
128
86
|
```
|
|
129
87
|
|
|
130
|
-
### Execute a command and use the values of a
|
|
88
|
+
### Execute a command and use the values of a `.env` file in its environment
|
|
131
89
|
|
|
132
|
-
Create a
|
|
90
|
+
Create a `.env` file if you don't have one already, and add some values:
|
|
133
91
|
|
|
134
92
|
```sh
|
|
135
|
-
echo "MY_FANCY_ENV_VAR='yes yes yallzies'\nHEY_HO='Let\'s go'" >
|
|
93
|
+
echo "MY_FANCY_ENV_VAR='yes yes yallzies'\nHEY_HO='Let\'s go'" > `.env`
|
|
136
94
|
```
|
|
137
95
|
|
|
138
|
-
The following command will create an encrypted version of the
|
|
96
|
+
The following command will create an encrypted version of the ``.env`` file, and store it in a file called ``.sec``. It will also create a config file called `dotsec.config.ts` which contains the KMS key alias, and AWS region. (Note: you don't have to add the key alias and region to the config file, you can also pass them as options to the dotsec aws sub command. See `dotsec init aws --help` for more information.)
|
|
139
97
|
|
|
140
98
|
```sh
|
|
141
99
|
npx dotsec init --aws-region eu-west-1 [--aws-key-alias alias/dotsec]
|
|
@@ -143,28 +101,28 @@ npx dotsec init --aws-region eu-west-1 [--aws-key-alias alias/dotsec]
|
|
|
143
101
|
|
|
144
102
|
The following files will be created:
|
|
145
103
|
|
|
146
|
-
-
|
|
104
|
+
- ``.sec`` - The encrypted version of the ``.env`` file.
|
|
147
105
|
- `dotsec.config.ts` - The config file containing the KMS key alias and AWS region.
|
|
148
106
|
|
|
149
107
|
### Add files to Git
|
|
150
108
|
|
|
151
|
-
Add the
|
|
109
|
+
Add the ``.sec`` and `dotsec.config.ts` files to your repository, and commit these accordingly.
|
|
152
110
|
|
|
153
|
-
### Run a process with your
|
|
111
|
+
### Run a process with your `.env` file
|
|
154
112
|
|
|
155
113
|
```sh
|
|
156
|
-
npx dotsec run --env
|
|
114
|
+
npx dotsec run --env `.env` command env
|
|
157
115
|
```
|
|
158
116
|
|
|
159
|
-
### Run a process with your
|
|
117
|
+
### Run a process with your `.sec` file
|
|
160
118
|
|
|
161
119
|
```sh
|
|
162
|
-
npx dotsec run --sec
|
|
120
|
+
npx dotsec run --sec `.sec` command env
|
|
163
121
|
```
|
|
164
122
|
|
|
165
123
|
For more options see `dotsec run --help`.
|
|
166
124
|
|
|
167
|
-
### Decrypt a
|
|
125
|
+
### Decrypt a `.sec` file to `.env`
|
|
168
126
|
|
|
169
127
|
```sh
|
|
170
128
|
npx dotsec decrypt
|
|
@@ -172,7 +130,7 @@ npx dotsec decrypt
|
|
|
172
130
|
|
|
173
131
|
For more options see `dotsec decrypt --help`.
|
|
174
132
|
|
|
175
|
-
### Encrypt a
|
|
133
|
+
### Encrypt a `.env` file to `.sec`
|
|
176
134
|
|
|
177
135
|
```sh
|
|
178
136
|
npx dotsec encrypt
|
|
@@ -180,7 +138,7 @@ npx dotsec encrypt
|
|
|
180
138
|
|
|
181
139
|
For more options see `dotsec encrypt --help`.
|
|
182
140
|
|
|
183
|
-
### Push selected
|
|
141
|
+
### Push selected `.env`/`.sec` entries to AWS Systems Manager Parameter Store
|
|
184
142
|
|
|
185
143
|
Take your favorite editor, and edit the `dotsec.config.ts` file. Add the following to the `aws` object:
|
|
186
144
|
|
|
@@ -204,7 +162,7 @@ Take your favorite editor, and edit the `dotsec.config.ts` file. Add the followi
|
|
|
204
162
|
npx dotsec push --env --to-aws-ssm
|
|
205
163
|
```
|
|
206
164
|
|
|
207
|
-
### Push selected
|
|
165
|
+
### Push selected `.env`/`.sec` entries to AWS Secrets Manager
|
|
208
166
|
|
|
209
167
|
Take your favorite editor, and edit the `dotsec.config.ts` file. Add the following to the `aws` object:
|
|
210
168
|
|
|
@@ -227,12 +185,12 @@ Take your favorite editor, and edit the `dotsec.config.ts` file. Add the followi
|
|
|
227
185
|
```sh
|
|
228
186
|
npx dotsec push --env --to-aws-secrets-manager
|
|
229
187
|
``` -->
|
|
230
|
-
|
|
188
|
+
<!--
|
|
231
189
|
### FAQ
|
|
232
190
|
|
|
233
|
-
#### Is it safe to commit a
|
|
191
|
+
#### Is it safe to commit a ``.sec`` and `dotsec.config.ts` file alongside your code?
|
|
234
192
|
|
|
235
|
-
Yes it is. But it is up to you to make sure that access to the KMS key is restricted to the people who need to decrypt and/or encrypt the
|
|
193
|
+
Yes it is. But it is up to you to make sure that access to the KMS key is restricted to the people who need to decrypt and/or encrypt the ``.sec`` file.
|
|
236
194
|
|
|
237
195
|
#### Should I use this in production?
|
|
238
196
|
|
|
@@ -243,15 +201,15 @@ We do, however, since this package is relatively new, I don't think you should.
|
|
|
243
201
|
- Write some tests already.
|
|
244
202
|
- Add support in-code use like `dotsec.config()`
|
|
245
203
|
- Add support for Node preload modules like `node -r dotsec/register index.js`
|
|
246
|
-
- Add watcher for
|
|
204
|
+
- Add watcher for ``.env`` file changes and automatically encrypt
|
|
247
205
|
- Write guide on postinstall for npm/yarn/pnpm
|
|
248
|
-
-
|
|
206
|
+
- Add chunking for encoding larger files with assymetric keys. Current limit is 4kb.
|
|
249
207
|
- Add support for other encryption SDKs like GCP KMS, Azure Key Vault, etc.
|
|
250
|
-
-
|
|
208
|
+
- Split up dotsec package in multiple packages, one for each encryption SDK.
|
|
251
209
|
- Add support for pulling entries to GitHub actions secrets.
|
|
252
210
|
|
|
253
211
|
## Limitations
|
|
254
212
|
|
|
255
213
|
- The only supported encryption SDK is the AWS Encryption SDK. For now.
|
|
256
|
-
-
|
|
257
|
-
- AWS Secrets Manager secrets which are marked for deletion **cannot** be updated until the deletion is complete. As of writing, the minimum deletion time is 7 days. This means that if you want to update a deleted AWS Secrets Manager secret, you have to wait at least 7 days before you can update it again. This is a limitation of AWS Secrets Manager, not dotsec
|
|
214
|
+
- Assymetric keys are supported, but the encrypted file size is limited to the payload size of the key. Until chunking is implemented, that is.
|
|
215
|
+
- AWS Secrets Manager secrets which are marked for deletion **cannot** be updated until the deletion is complete. As of writing, the minimum deletion time is 7 days. This means that if you want to update a deleted AWS Secrets Manager secret, you have to wait at least 7 days before you can update it again. This is a limitation of AWS Secrets Manager, not dotsec -->
|
package/dist/cli/index.js
CHANGED
|
@@ -1,29 +1,111 @@
|
|
|
1
|
-
var
|
|
2
|
-
The default file name is derived from the name of the encrypted file.
|
|
1
|
+
var je=Object.create;var J=Object.defineProperty;var Ve=Object.getOwnPropertyDescriptor;var Ae=Object.getOwnPropertyNames;var ke=Object.getPrototypeOf,He=Object.prototype.hasOwnProperty;var Le=(n,o,a,t)=>{if(o&&typeof o=="object"||typeof o=="function")for(let e of Ae(o))!He.call(n,e)&&e!==a&&J(n,e,{get:()=>o[e],enumerable:!(t=Ve(o,e))||t.enumerable});return n};var w=(n,o,a)=>(a=n!=null?je(ke(n)):{},Le(o||!n||!n.__esModule?J(a,"default",{value:n,enumerable:!0}):a,n));var Te=require("commander");var Re="dotsec.config.ts",B=[Re],q=".sec",G=".env",_={defaults:{}};var Y=w(require("fs")),z=w(require("path"));function Me(n){try{return new Function(`return ${n.trim()}`)()}catch{return{}}}var Q=async n=>{try{return Me(await Y.default.promises.readFile(n,"utf8"))}catch(o){throw o instanceof Error?new Error(`Failed to parse ${z.default.relative(process.cwd(),n)}: ${o.message}`):o}};var X=require("bundle-require"),Z=w(require("joycon")),ee=w(require("path")),ne=async n=>{let o=process.cwd(),t=await new Z.default().resolve({files:n?[n]:[...B,"package.json"],cwd:o,stopDir:ee.default.parse(o).root,packageKey:"dotsec"});if(n&&t===null)throw new Error(`Could not find config file ${n}`);if(t){if(t.endsWith(".json")){let e=await Q(t),i;return t.endsWith("package.json")&&e.dotsec!==void 0?i=e.dotsec:i=e,{source:"json",contents:{..._,...i,defaults:{...i?.defaults,..._.defaults,plugins:{...i?.defaults?.plugins,..._.defaults?.plugins}},push:{...i?.push}}}}else if(t.endsWith(".ts")){let e=await(0,X.bundleRequire)({filepath:t}),i=e.mod.dotsec||e.mod.default||e.mod;return{source:"ts",contents:{..._,...i,defaults:{...i?.defaults,..._.defaults,plugins:{...i?.defaults?.plugins,..._.defaults?.plugins}},push:{...i?.push}}}}}return{source:"defaultConfig",contents:_}};var W=async n=>import(n.name).then(o=>o.default);var te=require("commander"),x=(n,o,a)=>{n&&Object.values(n).map(t=>{let e;if(Array.isArray(t)){let[i,c,l]=t;e={flags:i,description:c,defaultValue:l}}else{let{flags:i,description:c,defaultValue:l,choices:s,env:r,fn:f}=t;e={flags:i,description:c,defaultValue:l,choices:s,env:r,fn:f}}if(e){let i=new te.Option(e.flags,e.description);e.fn&&i.argParser(e.fn),e.defaultValue&&i.default(e.defaultValue),e.env&&i.env(e.env),a&&i.makeOptionMandatory(!0),e.choices&&i.choices(e.choices),o.addOption(i)}})};var k=w(require("fs/promises")),oe=w(require("path")),ie=w(require("prompts")),V=async n=>await k.default.readFile(n,"utf-8"),I=async(n,o)=>await k.default.writeFile(n,o,"utf-8"),qe=async n=>{try{return await(0,k.stat)(n),!0}catch{return!1}},A=async({filePath:n,skip:o})=>{let a;return await qe(n)&&o!==!0?a=await(0,ie.default)({type:"confirm",name:"overwrite",message:()=>`Overwrite './${oe.default.relative(process.cwd(),n)}' ?`}):a=void 0,a};var re=w(require("chalk")),Ge=w(require("cli-table"));var C=n=>re.default.yellow.bold(n);var ye=require("commander");var S={option:["--env-file <envFile>",`Path to .env file. If not provided, will look for value in 'ENV_FILE' environment variable. If not provided, will look for '${G}' file in current directory.`,G],env:"ENV_FILE"},N={option:["--sec-file, <secFile>",`Path to .sec file. If not provided, will look for value in 'SEC_FILE' environment variable. If not provided, will look for '${q}' file in current directory.`,q],env:"SEC_FILE"},L={flags:"--using <using>",description:"Wether to use a dot env file or a dot sec file",choices:["env","sec"],env:"DOTSEC_USING"},se={flags:"--using <using>",description:"Wether to use a dot env file or a dot sec file",choices:["env"],env:"DOTSEC_USING"},$={option:["--yes","Skip confirmation prompts"]};var F={option:["-c, --config-file, --configFile <configFile>","Config file"],env:"DOTSEC_CONFIG_FILE"},ae={option:["--plugin <plugin>","Comma-separated list of plugins to use"],env:"DOTSEC_PLUGIN"},ce={option:["--engine <engine>","Encryption engine to use"],env:"DOTSEC_ENGINE"},R={option:["--create-manifest","Create a markdown manifest file. See the --manifest-file option for more information."],env:"CREATE_MANIFEST"},M={option:["--manifest-file <manifestFile>","Specify the name of the manifest file to create."],env:"ENCRYPTION_MANIFEST_FILE"};var We={decrypt:{options:{configFile:F,envFile:S,secFile:N,createManifest:R,manifestFile:M,yes:$},description:"Decrypt a sec file",helpText:`Examples:
|
|
3
2
|
|
|
4
|
-
See the --manifest-file option for more information.
|
|
5
|
-
`],env:"DOTSEC_ENCRYPTION_CREATE_MANIFEST"},manifestFile:{option:["--manifest-file <manifestFile>",`Specify the name of the manifest file to create.
|
|
6
|
-
This option is only used if the --create-manifest option is set to true.
|
|
7
3
|
|
|
8
|
-
|
|
4
|
+
Decrypt .sec file to .env file
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
`],env:"DOTSEC_ENCRYPTION_MANIFEST_FILE"},yes:$}}},ve=nt;var ot={init:{options:{verbose:["--verbose","Verbose output",!1],configFile:["-c, --config-file, --configFile <configFile>","Config file",K],envFile:T,secFile:k,yes:$}}},Ee=ot;var it={pull:{inheritsFrom:["dotsec"],options:{withEnv:U,withSec:G,envFile:T,secFile:k,yes:$}}},z=it;var rt={runEnvOnly:{inheritsFrom:["dotsec"],usage:"[commandArgs...]",options:{envFile:T,yes:$},description:"Run a command in a separate process and populate env with contents of a dotenv file.",helpText:`Examples:
|
|
6
|
+
$ npx dotsec decrypt
|
|
12
7
|
|
|
13
|
-
Run a command with a .env file
|
|
14
8
|
|
|
15
|
-
|
|
9
|
+
Specify a different .sec file
|
|
10
|
+
|
|
11
|
+
$ npx dotsec decrypt --sec-file .sec.dev
|
|
12
|
+
$ SEC_FILE=.sec.dev npx dotsec decrypt
|
|
13
|
+
|
|
14
|
+
Specify a different .env file
|
|
15
|
+
|
|
16
|
+
$ npx dotsec decrypt --env-file .env.dev
|
|
17
|
+
$ ENV_FILE=.env.dev npx dotsec decrypt
|
|
18
|
+
|
|
19
|
+
Write a manifest file
|
|
20
|
+
|
|
21
|
+
$ npx dotsec decrypt --create-manifest
|
|
22
|
+
$ CREATE_MANIFEST=true npx dotsec decrypt
|
|
23
|
+
|
|
24
|
+
Specify a different manifest file
|
|
25
|
+
|
|
26
|
+
$ npx dotsec decrypt --manifest-file .manifest.dev
|
|
27
|
+
$ MANIFEST_FILE=.manifest.dev npx dotsec decrypt
|
|
28
|
+
`}},pe=We;var Ue={dotsec:{options:{configFile:F,plugin:ae}}},le=Ue;var Ke={encrypt:{options:{configFile:F,envFile:S,secFile:N,createManifest:R,manifestFile:M,yes:$},description:"Encrypt an env file",helpText:`Examples:
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
Encrypt .env file to .sec file
|
|
32
|
+
|
|
33
|
+
$ npx dotsec encrypt
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
Specify a different .env file
|
|
37
|
+
|
|
38
|
+
$ npx dotsec encrypt --env-file .env.dev
|
|
39
|
+
$ ENV_FILE=.env.dev npx dotsec encrypt
|
|
40
|
+
|
|
41
|
+
Specify a different .sec file
|
|
42
|
+
|
|
43
|
+
$ npx dotsec encrypt --sec-file .sec.dev
|
|
44
|
+
$ SEC_FILE=.sec.dev npx dotsec encrypt
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
Write a manifest file
|
|
48
|
+
|
|
49
|
+
$ npx dotsec encrypt --create-manifest
|
|
50
|
+
$ CREATE_MANIFEST=true npx dotsec encrypt
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
Specify a different manifest file
|
|
54
|
+
|
|
55
|
+
$ npx dotsec encrypt --manifest-file .manifest.dev
|
|
56
|
+
$ MANIFEST_FILE=.manifest.dev npx dotsec encrypt
|
|
57
|
+
`}},de=Ke;var Je={init:{options:{configFile:F,yes:$},description:"Initialize a dotsec project by creating a dotsec.config.ts file.",helpText:`Examples:
|
|
58
|
+
|
|
59
|
+
Create a dotsec.config.ts file in the current directory
|
|
60
|
+
|
|
61
|
+
$ npx dotsec init
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
Overwrite an existing dotsec.config.ts file in the current directory
|
|
65
|
+
|
|
66
|
+
$ npx dotsec init --yes
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
Create a dotsec config file in the current directory with a specific config file name
|
|
70
|
+
|
|
71
|
+
By specifying the --config-file option, you can create a dotsec config file with a specific name.
|
|
72
|
+
|
|
73
|
+
$ npx dotsec init --config-file dotsec.config.ts
|
|
74
|
+
|
|
75
|
+
$ DOTSEC_CONFIG_FILE=my.config.ts npx dotsec init
|
|
76
|
+
`}},fe=Je;var Be={push:{options:{configFile:F,envFile:S,secFile:N,yes:$},requiredOptions:{using:L},description:"Push variables from env or sec file to a remote",helpText:`Examples:
|
|
77
|
+
|
|
78
|
+
Push variables from .env file to remote
|
|
79
|
+
|
|
80
|
+
$ npx dotsec push --using env
|
|
81
|
+
$ DOTSEC_USING=env npx dotsec push
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
Push variables from .sec file to remote
|
|
85
|
+
|
|
86
|
+
$ npx dotsec push --using sec
|
|
87
|
+
$ DOTSEC_USING=sec npx dotsec push
|
|
88
|
+
`}},me=Be;var Ye={runEnvOnly:{usage:"--using env [commandArgs...]",options:{configFile:F,envFile:S,yes:$,engine:ce},requiredOptions:{using:se},description:"Run a command in a separate process and populate env with contents of a dotenv file.",helpText:`Examples:
|
|
89
|
+
|
|
90
|
+
Run a command with a .env file
|
|
91
|
+
|
|
92
|
+
$ npx dotsec run --using env node -e "console.log(process.env)"
|
|
16
93
|
|
|
17
94
|
|
|
18
95
|
Run a command with a specific .env file
|
|
19
96
|
|
|
20
|
-
$ dotsec run --env-file .env
|
|
97
|
+
$ npx dotsec run --using env --env-file .env node -e "console.log(process.env)"
|
|
98
|
+
|
|
21
99
|
|
|
22
100
|
Run a command with a specific ENV_FILE variable
|
|
23
101
|
|
|
24
|
-
$ ENV_FILE=.env.dev dotsec run
|
|
102
|
+
$ ENV_FILE=.env.dev npx dotsec run --using env node -e "console.log(process.env)"
|
|
103
|
+
|
|
25
104
|
|
|
26
|
-
|
|
105
|
+
You can also specify 'using' as an environment variable
|
|
106
|
+
|
|
107
|
+
$ DOTSEC_USING=env npx dotsec run node -e "console.log(process.env)"
|
|
108
|
+
`},run:{options:{configFile:F,envFile:S,secFile:N,yes:$},requiredOptions:{using:L},usage:"[--using env] [--using sec] [commandArgs...]",description:`Run a command in a separate process and populate env with either
|
|
27
109
|
- contents of a dotenv file
|
|
28
110
|
- decrypted values of a dotsec file.
|
|
29
111
|
|
|
@@ -47,21 +129,39 @@ $ dotsec run --with-sec echo "hello world"
|
|
|
47
129
|
Run a command with a specific .sec file
|
|
48
130
|
|
|
49
131
|
$ dotsec run --with-sec --sec-file .sec.dev echo "hello world"
|
|
50
|
-
`}
|
|
132
|
+
`}},ge=Ye;var ze={...le,...fe,...de,...pe,...ge,...me},Qe=n=>{if(Array.isArray(n)){let[o,a,t]=n;return{flags:o,description:a,defaultValue:t}}else{if("option"in n){let[o,a,t]=n.option;return{flags:o,description:a,defaultValue:t,env:n.env}}return n}},ue=(n,o)=>{let a=o?.dotsecConfig?.defaults?.options?.[o?.optionKey],t=Qe(n),e=new ye.Option(t.flags,t.description);return t.fn&&e.argParser(t.fn),t.defaultValue&&e.default(a||t.defaultValue),t.env&&e.env(t.env),o.required&&e.makeOptionMandatory(!0),t.choices&&e.choices(t.choices),e},P=n=>{let{program:o,commandName:a,dotsecConfig:t}=n,e=ze[a||o.name()];if(e){let{options:i,requiredOptions:c,description:l,usage:s,helpText:r}=e;i&&Object.keys(i).forEach(f=>{let m=i[f],d=ue(m,{dotsecConfig:t,optionKey:f});o.addOption(d)}),c&&Object.keys(c).forEach(f=>{let m=c[f],d=ue(m,{required:!0,dotsecConfig:t,optionKey:f});o.addOption(d)}),l&&o.description(l),s&&o.usage(s),r&&o.description(r)}};var Oe=require("dotenv"),Xe=async(n,o)=>{let{dotsecConfig:a,decryptHandlers:t}=o,e=n.enablePositionalOptions().passThroughOptions().command("decrypt").action(async(c,l)=>{try{let{envFile:s,secFile:r,engine:f,createManifest:m,manifestFile:d,yes:p}=l.optsWithGlobals(),O=f||a?.defaults?.encryptionEngine,u=(t||[]).find(h=>h.triggerOptionValue===O);if(!u)throw new Error(`No decryption plugin found, available decryption engine(s): ${o.decryptHandlers.map(h=>`--${h.triggerOptionValue}`).join(", ")}`);console.log("Decrypting with",C(u.encryptionEngineName||u.triggerOptionValue),"engine");let g=[...Object.keys(u.options||{}),...Object.keys(u.requiredOptions||{})],D=Object.fromEntries(g.map(h=>[h,c[h]])),v=await V(r),E=await u.handler({ciphertext:v,...D}),j=await A({filePath:s,skip:p});if((j===void 0||j.overwrite===!0)&&(await I(s,E),console.log(`Wrote plaintext contents of ${C(r)} file to ${C(s)}`)),m){let h=(0,Oe.parse)(E),y=`# Dotsec decryption manifest
|
|
133
|
+
|
|
134
|
+
## Overview
|
|
135
|
+
|
|
136
|
+
- plaintext source: ${s}
|
|
137
|
+
- ciphertext target: ${r}
|
|
138
|
+
- created: ${new Date().toUTCString()}
|
|
139
|
+
- Decryption engine: ${u.encryptionEngineName||u.triggerOptionValue}
|
|
140
|
+
- Decryption engine options: ${JSON.stringify(D)}
|
|
141
|
+
|
|
142
|
+
## Variables
|
|
143
|
+
|
|
144
|
+
| Key |
|
|
145
|
+
| --- |
|
|
146
|
+
${Object.keys(h).map(H=>`| \`${H} \`| `).join(`
|
|
147
|
+
`)}
|
|
148
|
+
`,b=d||`${s}.decryption-manifest.md`;await I(b,y),console.log(`Wrote manifest of ${C(s)} file to ${C(b)}`)}}catch(s){console.error(C(s.message)),l.help()}});o.decryptHandlers.map(c=>{let{options:l,requiredOptions:s}=c;x(l,e),x(s,e,!0)});let i=o.decryptHandlers.map(c=>c.triggerOptionValue);return e.option("--engine <engine>",`Encryption engine${i.length>0?"s":""} to use: ${i.length===1?i[0]:i.join(", ")}`,i.length===1?i[0]:void 0),P({program:e,dotsecConfig:a}),e},Ce=Xe;var he=require("dotenv"),Ze=async(n,o)=>{let{encryptHandlers:a,dotsecConfig:t}=o,e=n.enablePositionalOptions().passThroughOptions().command("encrypt").action(async(l,s)=>{try{let{envFile:r,secFile:f,engine:m,createManifest:d,manifestFile:p,yes:O}=s.optsWithGlobals(),u=m||t?.defaults?.encryptionEngine,g=(a||[]).find(y=>y.triggerOptionValue===u);if(!g)throw new Error(`No encryption plugin found, available encryption engine(s): ${o.encryptHandlers.map(y=>y.triggerOptionValue).join(", ")}`);let D=[...Object.keys(g.options||{}),...Object.keys(g.requiredOptions||{})],v=Object.fromEntries(D.map(y=>[y,l[y]])),E=await V(r),j=await g.handler({plaintext:E,...v}),h=await A({filePath:f,skip:O});if((h===void 0||h.overwrite===!0)&&(await I(f,j),console.log(`Wrote encrypted contents of ${C(r)} file to ${C(f)}`),d)){let y=(0,he.parse)(E),b=`# Dotsec encryption manifest
|
|
51
149
|
|
|
52
150
|
## Overview
|
|
53
151
|
|
|
54
|
-
- plaintext source: ${
|
|
152
|
+
- plaintext source: ${r}
|
|
55
153
|
- ciphertext target: ${f}
|
|
56
154
|
- created: ${new Date().toUTCString()}
|
|
57
|
-
- encryption engine: ${
|
|
58
|
-
- encryption engine options: ${JSON.stringify(
|
|
155
|
+
- encryption engine: ${g.encryptionEngineName||g.triggerOptionValue}
|
|
156
|
+
- encryption engine options: ${JSON.stringify(v)}
|
|
59
157
|
|
|
60
158
|
## Variables
|
|
61
159
|
|
|
62
160
|
| Key |
|
|
63
161
|
| --- |
|
|
64
|
-
${Object.keys(
|
|
162
|
+
${Object.keys(y).map(Ne=>`| \`${Ne} \`| `).join(`
|
|
65
163
|
`)}
|
|
66
|
-
`,
|
|
67
|
-
|
|
164
|
+
`,H=p||`${f}.encryption-manifest.md`;await I(H,b),console.log(`Wrote manifest of ${C(r)} file to ${C(H)}`)}}catch(r){console.error(C(r.message)),s.help()}});o.encryptHandlers.map(l=>{let{options:s,requiredOptions:r}=l;x(s,e),x(r,e,!0)});let i=o.encryptHandlers.map(l=>l.triggerOptionValue),c=o.encryptHandlers.map(l=>l.encryptionEngineName);return e.option("--engine <engine>",`Encryption engine${i.length>0?"s":""}: ${i.length===1?i[0]:i.join(", ")}`,i.length===1?i[0]:void 0),P({program:e,dotsecConfig:t}),e.description(`Encrypt .env file using ${c.join(", ")}`),e},ve=Ze;var Ee=w(require("path")),en=async(n,o)=>{let{dotsecConfig:a}=o,t=n.enablePositionalOptions().passThroughOptions().command("init").action(async(e,i)=>{let{configFile:c="dotsec.config.ts",yes:l}=i.optsWithGlobals();try{let s=await V(Ee.default.resolve(__dirname,"../../src/templates/dotsec.config.ts")),r=await A({filePath:c,skip:l});(r===void 0||r.overwrite===!0)&&(await I(c,s),console.log(`Wrote config file to ${C(c)}`))}catch(s){i.error(s)}});return P({program:t,dotsecConfig:a}),t},we=en;var De=require("dotenv"),Fe=require("dotenv-expand"),U=w(require("fs")),nn=async(n,o)=>{let{dotsecConfig:a,handlers:t}=o,e=n.enablePositionalOptions().passThroughOptions().command("push").action(async(r,f)=>{try{let{using:m,envFile:d,secFile:p,engine:O,yes:u}=f.optsWithGlobals(),g=O||a?.defaults?.encryptionEngine,D=(t||[]).find(y=>y.decrypt?.triggerOptionValue===g)?.decrypt,v=(t||[]).find(y=>y.push?.triggerOptionValue===g)?.push;if(!v)throw new Error("No push plugin found!");let E=[...Object.keys(D?.options||{}),...Object.keys(D?.requiredOptions||{}),...Object.keys(v?.options||{}),...Object.keys(v?.requiredOptions||{})],j=Object.fromEntries(E.map(y=>[y,r[y]])),h;if(m==="env"){if(!d)throw new Error("No dotenv file specified in --env-file option");h=U.default.readFileSync(d,"utf8")}else{if(!p)throw new Error("No dotsec file specified in --sec-file option");if(!D)throw new Error(`No decryption plugin found, available decryption engine(s): ${t.map(b=>`--${b.decrypt?.triggerOptionValue}`).join(", ")}`);let y=U.default.readFileSync(p,"utf8");h=await D.handler({ciphertext:y,...j})}if(h){let y=(0,De.parse)(h),b=(0,Fe.expand)({ignoreProcessEnv:!0,parsed:{...process.env,...y}});b.parsed&&await v.handler({push:b.parsed,yes:u,...j})}else throw new Error("No .env or .sec file provided")}catch(m){console.error(m),process.exit(1)}});P({program:e,dotsecConfig:a});let i=o.handlers.map(({decrypt:r})=>r.triggerOptionValue);e.option("--engine <engine>",`Encryption engine${i.length>0?"s":""} to use: ${i.length===1?i[0]:i.join(", ")}`,i.length===1?i[0]:void 0);let c={};o.handlers.forEach(r=>{Object.keys(r).map(f=>{let{options:m,requiredOptions:d}=r[f];Object.keys(m||{}).forEach(p=>{c[p]=Array.isArray(m[p])?m[p]:{...c[p],...m[p]}}),Object.keys(d||{}).forEach(p=>{c[p]=Array.isArray(d[p])?d[p]:{...c[p],...d[p],required:!0}})})});let l=[],s=[];return t.forEach(r=>{r.push?.description&&s.push(r.push.description),r.push?.usage&&l.push(r.push.usage)}),s.length>0&&e.description(s.join(`
|
|
165
|
+
`)),l.length>0&&e.usage(l.join(`
|
|
166
|
+
`)),x(Object.fromEntries(Object.entries(c).filter(([r,f])=>f.required!==!0)),e),x(Object.fromEntries(Object.entries(c).filter(([r,f])=>f.required===!0)),e,!0),e},xe=nn;var K=w(require("fs")),Pe=require("dotenv"),$e=require("dotenv-expand");var be=require("child_process"),tn=(n,o)=>{let{dotsecConfig:a,decryptHandlers:t}=o||{},e=t!==void 0&&t.length>0,i=n.command("run <command...>").allowUnknownOption(!0).enablePositionalOptions().passThroughOptions().showHelpAfterError(!0).action(async(c,l,s)=>{try{let{envFile:r,using:f,secFile:m,engine:d}=s.optsWithGlobals(),p;if(f==="env"||e===!1){if(!r)throw new Error("No dotenv file specified in --env-file option");p=K.default.readFileSync(r,"utf8")}else if(f==="sec"){if(!m)throw new Error("No dotsec file specified in --sec-file option");let O=d||a?.defaults?.encryptionEngine,u=(t||[]).find(E=>E.triggerOptionValue===O);if(!u)throw new Error(`No decryption plugin found, available decryption engine(s): ${(t||[]).map(E=>`--${E.triggerOptionValue}`).join(", ")}`);let g=[...Object.keys(u.options||{}),...Object.keys(u.requiredOptions||{})],D=Object.fromEntries(g.map(E=>[E,l[E]])),v=K.default.readFileSync(m,"utf8");p=await u.handler({ciphertext:v,...D})}if(p){let O=(0,Pe.parse)(p),u=(0,$e.expand)({ignoreProcessEnv:!0,parsed:{...process.env,...O}}),[g,...D]=c,v=(0,be.spawnSync)(g,[...D],{stdio:"inherit",shell:!1,encoding:"utf-8",env:{...u.parsed,...process.env,__DOTSEC_ENV__:JSON.stringify(Object.keys(O))}});v.status!==0&&process.exit(v.status||1)}else throw new Error("No .env or .sec file provided")}catch(r){console.error(C(r.message)),s.help()}});if(P({program:i,commandName:e?"run":"runEnvOnly",dotsecConfig:a}),e){t?.map(l=>{let{options:s,requiredOptions:r}=l;x(s,i),x(r,i,!0)});let c=t?.map(l=>l.triggerOptionValue);i.option("--engine <engine>",`Encryption engine${c.length>0?"s":""}: ${c.join(", "),c.length===1?c[0]:void 0}`)}return i},Se=tn;var _e=w(require("ajv")),Ie=w(require("yargs-parser")),on={keyword:"separator",type:"string",metaSchema:{type:"string",description:"value separator"},modifying:!0,valid:!0,errors:!1,compile:n=>(o,a)=>{if(a){let{parentData:t,parentDataProperty:e}=a;return t[e]=o===""?[]:o.split(n),!0}else return!1}},T=new Te.Command;(async()=>{let n=(0,Ie.default)(process.argv),o=[];n.plugin&&(Array.isArray(n.plugin)?o.push(...n.plugin):o.push(n.plugin));let a=[...Array.isArray(n.configFile)?n.configFile:[n.configFile],...Array.isArray(n.c)?n.c:[n.c]][0]||process.env.DOTSEC_CONFIG_FILE,{contents:t={}}=await ne(a),{defaults:e={},push:i,plugins:c}=t;T.name("dotsec").description(".env, but secure").version("1.0.0").enablePositionalOptions().action((d,p)=>{p.help()}),P({program:T,dotsecConfig:t});let l=new _e.default({allErrors:!0,removeAdditional:!0,useDefaults:!0,coerceTypes:!0,allowUnionTypes:!0,addUsedSchema:!1,keywords:[on]}),s={};if(c)for(let d of c)e?.plugins?.[d]||(e.plugins={...e.plugins,[d]:{}});if(o.length>0)for(let d of o){let O=await(await W({name:d}))({dotsecConfig:t,ajv:l,configFile:a});s[O.name]=d,o.length===1&&(t.defaults={...t.defaults,encryptionEngine:String(O.name),plugins:{...t.defaults?.plugins,[O.name]:{...t.defaults?.plugins?.[O.name]}}})}e?.encryptionEngine&&(e?.plugins?.[e.encryptionEngine]||(e.plugins={...e.plugins,[e.encryptionEngine]:{}})),e?.plugins&&Object.entries(e?.plugins).forEach(([d,p])=>{p?.name?s[d]=p?.name:s[d]=`@dotsec/plugin-${d}`}),Object.values(i||{}).forEach(d=>{Object.keys(d).forEach(p=>{s[p]||(s[p]=`@dotsec/plugin-${p}`)})});let r=[],f=[],m=[];for(let d of Object.keys(s)){let p=s[d],O=await W({name:p}),{addCliCommand:u,cliHandlers:g}=await O({ajv:l,dotsecConfig:t,configFile:a});g?.encrypt&&r.push(g.encrypt),g?.decrypt&&(f.push(g.decrypt),g?.push&&m.push({push:g.push,decrypt:g.decrypt})),u&&u({program:T})}r.length&&await ve(T,{dotsecConfig:t,encryptHandlers:r}),f.length&&await Ce(T,{dotsecConfig:t,decryptHandlers:f}),m.length&&await xe(T,{dotsecConfig:t,handlers:m}),await we(T,{dotsecConfig:t}),await Se(T,{dotsecConfig:t,decryptHandlers:f}),await T.parse()})();
|
|
167
|
+
//# sourceMappingURL=index.js.map
|