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 CHANGED
@@ -1,7 +1,45 @@
1
1
  # dotsec
2
2
 
3
- The solution offers encryption and decryption of `.env` files to and from `.sec` files, the ability to run a command with the values of a `.env`/`.sec` file in its environment, and the ability to push selected `.env`/`.sec` entries to AWS Systems Manager Parameter Store and AWS Secrets Manager.
4
- Encrypts your `.env` file with the AWS Encryption SDK so you can safely commit it to your repository.
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 .env file in its environment
88
+ ### Execute a command and use the values of a `.env` file in its environment
131
89
 
132
- Create a .env file if you don't have one already, and add some values:
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'" > .env
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 `.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.)
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
- - `.sec` - The encrypted version of the `.env` file.
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 `.sec` and `dotsec.config.ts` files to your repository, and commit these accordingly.
109
+ Add the ``.sec`` and `dotsec.config.ts` files to your repository, and commit these accordingly.
152
110
 
153
- ### Run a process with your .env file
111
+ ### Run a process with your `.env` file
154
112
 
155
113
  ```sh
156
- npx dotsec run --env .env command env
114
+ npx dotsec run --env `.env` command env
157
115
  ```
158
116
 
159
- ### Run a process with your .sec file
117
+ ### Run a process with your `.sec` file
160
118
 
161
119
  ```sh
162
- npx dotsec run --sec .sec command env
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 .sec file to .env
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 .env file to .sec
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 .env/.sec entries to AWS Systems Manager Parameter Store
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 .env/.sec entries to AWS Secrets Manager
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 `.sec` and `dotsec.config.ts` file alongside your code?
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 `.sec` file.
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 `.env` file changes and automatically encrypt
204
+ - Add watcher for ``.env`` file changes and automatically encrypt
247
205
  - Write guide on postinstall for npm/yarn/pnpm
248
- - ~~Add chunking for encoding larger files with assymetric keys. Current limit is 4kb.~~
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
- - ~~Split up dotsec package in multiple packages, one for each encryption SDK.~~
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
- - ~~Assymetric keys are supported, but the encrypted file size is limited to the payload size of the key. Until chunking is implemented, that is.~~
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 We=Object.create;var B=Object.defineProperty,Ue=Object.defineProperties,Ge=Object.getOwnPropertyDescriptor,Me=Object.getOwnPropertyDescriptors,Je=Object.getOwnPropertyNames,re=Object.getOwnPropertySymbols,Be=Object.getPrototypeOf,se=Object.prototype.hasOwnProperty,Ye=Object.prototype.propertyIsEnumerable;var ae=(e,t,r)=>t in e?B(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,c=(e,t)=>{for(var r in t||(t={}))se.call(t,r)&&ae(e,r,t[r]);if(re)for(var r of re(t))Ye.call(t,r)&&ae(e,r,t[r]);return e},S=(e,t)=>Ue(e,Me(t)),ze=e=>B(e,"__esModule",{value:!0});var Qe=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Je(t))!se.call(e,n)&&n!=="default"&&B(e,n,{get:()=>t[n],enumerable:!(r=Ge(t,n))||r.enumerable});return e},y=e=>Qe(ze(B(e!=null?We(Be(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var Le=y(require("commander"));var K="dotsec.config.ts",ce=[K],Q=".sec",X=".env",V={defaults:{encryptionEngine:"pke",plugins:{pke:{}}}};var pe=y(require("fs")),le=y(require("node:path"));function Xe(e){try{return new Function(`return ${e.trim()}`)()}catch{return{}}}var me=async e=>{try{return Xe(await pe.default.promises.readFile(e,"utf8"))}catch(t){throw t instanceof Error?new Error(`Failed to parse ${le.default.relative(process.cwd(),e)}: ${t.message}`):t}};var de=y(require("bundle-require")),fe=y(require("joycon")),ue=y(require("path")),ge=async e=>{var o,a,l,s;let t=process.cwd(),n=await new fe.default().resolve({files:e?[e]:[...ce,"package.json"],cwd:t,stopDir:ue.default.parse(t).root,packageKey:"dotsec"});if(e&&n===null)throw new Error(`Could not find config file ${e}`);if(n){if(n.endsWith(".json")){let p=await me(n),i;return n.endsWith("package.json")&&p.dotsec!==void 0?i=p.dotsec:i=p,{source:"json",contents:S(c(c({},V),i),{defaults:S(c(c({},i==null?void 0:i.defaults),V.defaults),{plugins:c(c({},(o=i==null?void 0:i.defaults)==null?void 0:o.plugins),(a=V.defaults)==null?void 0:a.plugins)}),push:c({},i==null?void 0:i.push)})}}else if(n.endsWith(".ts")){let p=await(0,de.bundleRequire)({filepath:n}),i=p.mod.dotsec||p.mod.default||p.mod;return{source:"ts",contents:S(c(c({},V),i),{defaults:S(c(c({},i==null?void 0:i.defaults),V.defaults),{plugins:c(c({},(l=i==null?void 0:i.defaults)==null?void 0:l.plugins),(s=V.defaults)==null?void 0:s.plugins)}),push:c({},i==null?void 0:i.push)})}}}return{source:"defaultConfig",contents:V}};var Z=async e=>Promise.resolve().then(()=>y(require(e.name))).then(t=>t.default);var ye=y(require("commander")),j=(e,t,r)=>{e&&Object.values(e).map(n=>{let o;if(Array.isArray(n)){let[a,l,s]=n;o={flags:a,description:l,defaultValue:s}}else{let{flags:a,description:l,defaultValue:s,env:p,fn:i}=n;o={flags:a,description:l,defaultValue:s,env:p,fn:i}}if(o){let a=new ye.Option(o.flags,o.description);o.fn&&a.argParser(o.fn),o.defaultValue&&a.default(o.defaultValue),o.env&&a.env(o.env),r&&a.makeOptionMandatory(!0),t.addOption(a)}})};var W=y(require("node:fs/promises")),he=y(require("node:path")),Ce=y(require("prompts")),Y=async e=>await W.default.readFile(e,"utf-8"),H=async(e,t)=>await W.default.writeFile(e,t,"utf-8"),Ze=async e=>{try{return await(0,W.stat)(e),!0}catch{return!1}},L=async({filePath:e,skip:t})=>{let r;return await Ze(e)&&t!==!0?r=await(0,Ce.default)({type:"confirm",name:"overwrite",message:()=>`Overwrite './${he.default.relative(process.cwd(),e)}' ?`}):r=void 0,r};var Oe=y(require("chalk")),Ft=require("cli-table");var b=e=>Oe.default.yellow.bold(e);var Fe=y(require("commander"));var T={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 '${X}' file in current directory.`,X],env:"ENV_FILE"},k={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"},U={option:["--with-env, --withEnv","Run command using a dot env file"]},G={option:["--with-sec, --withSec","Run command with a dotsec file"]},$={option:["--yes","Skip confirmation prompts"]};var et={decrypt:{inheritsFrom:["dotsec"],options:{envFile:T,secFile:k,yes:$}}},we=et;var tt={dotsec:{options:{verbose:["--verbose","Verbose output",!1],configFile:["-c, --config-file, --configFile <configFile>","Config file",K],plugin:["--plugin <plugin>","Comma-separated list of plugins to use"]}}},M=tt;var nt={encrypt:{inheritsFrom:["dotsec"],options:{envFile:T,secFile:k,createManifest:{option:["--create-manifest",`Create a markdown manifest file containing the source of the encrypted variables, encryption method etc as well as the names of the encrypted variables. Be careful, this file will contain the names of the encrypted variables in plain text.
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
- If this option is not specified, the default name will be derived from the name of the encrypted file.
4
+ Decrypt .sec file to .env file
9
5
 
10
- For example, if the encrypted file is named ".sec", the manifest file will be named ".sec.encryption-manifest.md".
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
- $ dotsec run echo "hello world"
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.dev echo "hello world"
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 echo "hello world"
102
+ $ ENV_FILE=.env.dev npx dotsec run --using env node -e "console.log(process.env)"
103
+
25
104
 
26
- `},run:{inheritsFrom:["dotsec"],options:{withEnv:U,withSec:G,envFile:T,secFile:k,yes:$},usage:"[--with-env --env-file .env] [--with-sec --sec-file .sec] [commandArgs...]",description:`Run a command in a separate process and populate env with either
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
- `},push:{options:S(c({},M.dotsec.options),{withEnv:U,withSec:G,envFile:T,secFile:k,yes:$}),requiredOptions:c({},M.dotsec.requiredOptions)}},De=rt;var st=c(c(c(c(c(c(c({},M),Ee),ve),we),De),z),z);var at=e=>Array.isArray(e)?{option:e}:e,Pe=(e,t)=>{var p,i,d;let r=at(e),[n,o,a]=r.option,l=(d=(i=(p=t==null?void 0:t.dotsecConfig)==null?void 0:p.defaults)==null?void 0:i.options)==null?void 0:d[t==null?void 0:t.optionKey],s=new Fe.Option(n,o+(l?". Default from config.":""));return a&&s.default(l||a),r.env&&s.env(r.env),(t==null?void 0:t.required)&&s.makeOptionMandatory(!0),s},_=e=>{let{program:t,commandName:r,dotsecConfig:n}=e,o=st[r||t.name()];if(o){let{options:a,requiredOptions:l,description:s,usage:p,helpText:i}=o;a&&Object.keys(a).forEach(d=>{let f=a[d],w=Pe(f,{dotsecConfig:n,optionKey:d});t.addOption(w)}),l&&Object.keys(l).forEach(d=>{let f=l[d],w=Pe(f,{required:!0,dotsecConfig:n,optionKey:d});t.addOption(w)}),s&&t.description(s),p&&t.description(p),i&&t.description(i)}};var ct=async(e,t)=>{let{dotsecConfig:r,decryptHandlers:n}=t,o=e.enablePositionalOptions().passThroughOptions().command("decrypt").action(async(l,s)=>{var p;try{let{envFile:i,secFile:d,engine:f,yes:w}=s.optsWithGlobals(),F=f||((p=r==null?void 0:r.defaults)==null?void 0:p.encryptionEngine),D=(n||[]).find(v=>v.triggerOptionValue===F);if(!D)throw new Error(`No decryption plugin found, available decryption engine(s): ${t.decryptHandlers.map(v=>`--${v.triggerOptionValue}`).join(", ")}`);console.log("Decrypting with",b(D.encryptionEngineName||D.triggerOptionValue),"engine");let h=[...Object.keys(D.options||{}),...Object.keys(D.requiredOptions||{})],u=Object.fromEntries(h.map(v=>[v,l[v]])),m=await Y(d),C=await D.handler(c({ciphertext:m},u)),g=await L({filePath:i,skip:w});(g===void 0||g.overwrite===!0)&&(await H(i,C),console.log(`Wrote plaintext contents of ${b(d)} file to ${b(i)}`))}catch(i){console.error(b(i.message)),s.help()}});t.decryptHandlers.map(l=>{let{options:s,requiredOptions:p}=l;j(s,o),j(p,o,!0)});let a=t.decryptHandlers.map(l=>l.triggerOptionValue);return o.option("--engine <engine>",`Encryption engine${a.length>0?"s":""} to use: ${a.length===1?a[0]:a.join(", ")}`,a.length===1?a[0]:void 0),_({program:o,dotsecConfig:r}),o},xe=ct;var be=y(require("dotenv")),pt=async(e,t)=>{let{encryptHandlers:r,dotsecConfig:n}=t,o=e.enablePositionalOptions().passThroughOptions().command("encrypt").action(async(s,p)=>{var i;try{let{envFile:d,secFile:f,engine:w,createManifest:F,manifestFile:D,yes:h}=p.optsWithGlobals(),u=w||((i=n==null?void 0:n.defaults)==null?void 0:i.encryptionEngine),m=(r||[]).find(O=>O.triggerOptionValue===u);if(!m)throw new Error(`No encryption plugin found, available encryption engine(s): ${t.encryptHandlers.map(O=>O.triggerOptionValue).join(", ")}`);console.log("Encrypting with",b(m.encryptionEngineName||m.triggerOptionValue),"engine");let C=[...Object.keys(m.options||{}),...Object.keys(m.requiredOptions||{})],g=Object.fromEntries(C.map(O=>[O,s[O]])),v=await Y(d),P=await m.handler(c({plaintext:v},g)),x=await L({filePath:f,skip:h});if((x===void 0||x.overwrite===!0)&&(await H(f,P),console.log(`Wrote encrypted contents of ${b(d)} file to ${b(f)}`),F)){let O=(0,be.parse)(v),I=`# Dotsec encryption manifest
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: ${d}
152
+ - plaintext source: ${r}
55
153
  - ciphertext target: ${f}
56
154
  - created: ${new Date().toUTCString()}
57
- - encryption engine: ${m.encryptionEngineName||m.triggerOptionValue}
58
- - encryption engine options: ${JSON.stringify(g)}
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(O).map(J=>`| \`${J} \`| `).join(`
162
+ ${Object.keys(y).map(Ne=>`| \`${Ne} \`| `).join(`
65
163
  `)}
66
- `,q=D||`${f}.encryption-manifest.md`;await H(q,I),console.log(`Wrote manifest of ${b(d)} file to ${b(q)}`)}}catch(d){console.error(b(d.message)),p.help()}});t.encryptHandlers.map(s=>{let{options:p,requiredOptions:i}=s;j(p,o),j(i,o,!0)});let a=t.encryptHandlers.map(s=>s.triggerOptionValue),l=t.encryptHandlers.map(s=>s.encryptionEngineName);return o.option("--engine <engine>",`Encryption engine${a.length>0?"s":""}: ${a.length===1?a[0]:a.join(", ")}`),_({program:o,dotsecConfig:n}),o.description(`Encrypt .env file using ${l.join(", ")}`),o},Se=pt;var Te=y(require("node:fs")),E=y(require("typescript")),$e=e=>{let t=E.createPrinter(),r=Te.default.readFileSync(e.configFile,"utf8"),n=p=>i=>{function d(f){var w,F,D,h,u,m,C,g,v,P,x,O,I,q,J,ne,oe,ie;if(f=E.visitEachChild(f,d,p),f.kind===E.SyntaxKind.StringLiteral){let R=(F=(w=f==null?void 0:f.parent)==null?void 0:w.parent)==null?void 0:F.parent;if(((u=(h=(D=e.config)==null?void 0:D.aws)==null?void 0:h.kms)==null?void 0:u.keyAlias)&&((m=R==null?void 0:R.getChildAt(0))==null?void 0:m.getText())==="kms"){let N=(C=R==null?void 0:R.parent)==null?void 0:C.parent;if((N==null?void 0:N.getChildAt(0).getText())==="aws")return E.createStringLiteral((P=(v=(g=e.config)==null?void 0:g.aws)==null?void 0:v.kms)==null?void 0:P.keyAlias)}if(((O=(x=e.config)==null?void 0:x.aws)==null?void 0:O.region)&&((q=(I=f==null?void 0:f.parent)==null?void 0:I.getChildAt(0))==null?void 0:q.getText())==="region"){let N=(ne=(J=f==null?void 0:f.parent)==null?void 0:J.parent)==null?void 0:ne.parent;if((N==null?void 0:N.getChildAt(0).getText())==="aws")return E.createStringLiteral((ie=(oe=e.config)==null?void 0:oe.aws)==null?void 0:ie.region)}}return f}return E.visitNode(i,d)},o=E.createSourceFile("test.ts",r,E.ScriptTarget.ES2015,!0,E.ScriptKind.TS),a=E.transform(o,[n]),l=a.transformed[0],s=t.printFile(l);return a.dispose(),s};var _e=y(require("node:path")),lt=async(e,t)=>{let{dotsecConfig:r}=t,n=e.enablePositionalOptions().passThroughOptions().command("init").action(async(o,a)=>{let{configFile:l,yes:s}=a.optsWithGlobals();try{let p=$e({configFile:_e.default.resolve(__dirname,"../../src/templates/dotsec.config.ts")}),i=await L({filePath:l,skip:s});(i===void 0||i.overwrite===!0)&&(await H(l,p),console.log(`Wrote config file to ${b(l)}`))}catch(p){a.error(p)}});return _({program:n,dotsecConfig:r}),n},ke=lt;var je=y(require("dotenv")),Ae=y(require("dotenv-expand")),ee=y(require("node:fs")),mt=async(e,t)=>{let{dotsecConfig:r,handlers:n}=t,o=e.enablePositionalOptions().passThroughOptions().command("push").action(async(a,l)=>{var s,p,i;try{let{envFile:d,secFile:f,withEnv:w,withSec:F,engine:D,yes:h}=l.optsWithGlobals(),u=D||((s=r==null?void 0:r.defaults)==null?void 0:s.encryptionEngine),m=(p=(n||[]).find(x=>{var O;return((O=x.decrypt)==null?void 0:O.triggerOptionValue)===u}))==null?void 0:p.decrypt,C=(i=(n||[]).find(x=>{var O;return((O=x.push)==null?void 0:O.triggerOptionValue)===u}))==null?void 0:i.push;if(!C)throw new Error("No push plugin found!");let g=[...Object.keys((m==null?void 0:m.options)||{}),...Object.keys((m==null?void 0:m.requiredOptions)||{}),...Object.keys((C==null?void 0:C.options)||{}),...Object.keys((C==null?void 0:C.requiredOptions)||{})],v=Object.fromEntries(g.map(x=>[x,a[x]]));if(w&&F)throw new Error("Cannot use both --with-env and --with-sec");let P;if(w||!(w||F)){if(!d)throw new Error("No dotenv file specified in --env-file option");P=ee.default.readFileSync(d,"utf8")}else if(F){if(!f)throw new Error("No dotsec file specified in --sec-file option");if(!m)throw new Error(`No decryption plugin found, available decryption engine(s): ${n.map(O=>{var I;return`--${(I=O.decrypt)==null?void 0:I.triggerOptionValue}`}).join(", ")}`);let x=ee.default.readFileSync(f,"utf8");P=await m.handler(c({ciphertext:x},v))}if(P){let x=(0,je.parse)(P),O=(0,Ae.expand)({ignoreProcessEnv:!0,parsed:c(c({},process.env),x)});O.parsed&&await C.handler(c({push:O.parsed,yes:h},v))}else throw new Error("No .env or .sec file provided")}catch(d){console.error(d),process.exit(1)}});return _({program:o,dotsecConfig:r}),o},Ve=mt;var te=y(require("node:fs")),Ie=y(require("dotenv")),Ne=y(require("dotenv-expand"));var He=y(require("node:child_process")),dt=(e,t)=>{let{dotsecConfig:r,decryptHandlers:n}=t||{},o=n!==void 0&&n.length>0,a=e.command("run <command...>").allowUnknownOption(!0).enablePositionalOptions().passThroughOptions().showHelpAfterError(!0).action(async(l,s,p)=>{var i;try{let{envFile:d,secFile:f,withEnv:w,withSec:F,engine:D}=p.optsWithGlobals();if(w&&F)throw new Error("Cannot use both --with-env and --with-sec");let h;if(w||!(w||F)||o===!1){if(!d)throw new Error("No dotenv file specified in --env-file option");h=te.default.readFileSync(d,"utf8")}else if(F){if(!f)throw new Error("No dotsec file specified in --sec-file option");let u=D||((i=r==null?void 0:r.defaults)==null?void 0:i.encryptionEngine),m=(n||[]).find(P=>P.triggerOptionValue===u);if(!m)throw new Error(`No decryption plugin found, available decryption engine(s): ${(n||[]).map(P=>`--${P.triggerOptionValue}`).join(", ")}`);let C=[...Object.keys(m.options||{}),...Object.keys(m.requiredOptions||{})],g=Object.fromEntries(C.map(P=>[P,s[P]])),v=te.default.readFileSync(f,"utf8");h=await m.handler(c({ciphertext:v},g))}if(h){let u=(0,Ie.parse)(h),m=(0,Ne.expand)({ignoreProcessEnv:!0,parsed:c(c({},process.env),u)}),[C,...g]=l,v=(0,He.spawnSync)(C,[...g],{stdio:"inherit",shell:!1,encoding:"utf-8",env:S(c(c({},m.parsed),process.env),{__DOTSEC_ENV__:JSON.stringify(Object.keys(u))})});v.status!==0&&process.exit(v.status||1)}else throw new Error("No .env or .sec file provided")}catch(d){console.error(b(d.message)),p.help()}});if(_({program:a,commandName:o?"run":"runEnvOnly",dotsecConfig:r}),o){n==null||n.map(s=>{let{options:p,requiredOptions:i}=s;j(p,a),j(i,a,!0)});let l=n==null?void 0:n.map(s=>s.triggerOptionValue);a.option("--engine <engine>",`Encryption engine${l.length>0?"s":""}: ${l.join(", "),l.length===1?l[0]:void 0}`)}return a},Re=dt;var qe=y(require("ajv")),Ke=y(require("yargs-parser")),ft={keyword:"separator",type:"string",metaSchema:{type:"string",description:"value separator"},modifying:!0,valid:!0,errors:!1,compile:e=>(t,r)=>{if(r){let{parentData:n,parentDataProperty:o}=r;return n[o]=t===""?[]:t.split(e),!0}else return!1}},A=new Le.Command;(async()=>{var f,w,F,D;let e=(0,Ke.default)(process.argv),t=[];e.plugin&&(Array.isArray(e.plugin)?t.push(...e.plugin):t.push(e.plugin));let r=[...Array.isArray(e.config)?e.config:[e.config],...Array.isArray(e.c)?e.c:[e.c]][0],{contents:n={}}=await ge(r),{defaults:o,push:a}=n;A.name("dotsec").description(".env, but secure").version("1.0.0").enablePositionalOptions().action((h,u)=>{u.help()}),_({program:A,dotsecConfig:n});let l=new qe.default({allErrors:!0,removeAdditional:!0,useDefaults:!0,coerceTypes:!0,allowUnionTypes:!0,addUsedSchema:!1,keywords:[ft]}),s={};if(t.length>0)for(let h of t){let m=await(await Z({name:h}))({dotsecConfig:n,ajv:l,configFile:r});s[m.name]=h,t.length===1&&(n.defaults=S(c({},n.defaults),{encryptionEngine:String(m.name),plugins:S(c({},(f=n.defaults)==null?void 0:f.plugins),{[m.name]:c({},(F=(w=n.defaults)==null?void 0:w.plugins)==null?void 0:F[m.name])})}))}(o==null?void 0:o.encryptionEngine)&&(((D=o==null?void 0:o.plugins)==null?void 0:D[o.encryptionEngine])||(o.plugins=S(c({},o.plugins),{[o.encryptionEngine]:{}}))),(o==null?void 0:o.plugins)&&Object.entries(o==null?void 0:o.plugins).forEach(([h,u])=>{(u==null?void 0:u.module)?s[h]=u==null?void 0:u.module:s[h]=`@dotsec/plugin-${h}`}),Object.values(a||{}).forEach(h=>{Object.keys(h).forEach(u=>{s[u]||(s[u]=`@dotsec/plugin-${u}`)})});let p=[],i=[],d=[];for(let h of Object.keys(s)){let u=s[h],m=await Z({name:u}),{addCliCommand:C,cliHandlers:g}=await m({ajv:l,dotsecConfig:n,configFile:r});(g==null?void 0:g.encrypt)&&p.push(g.encrypt),(g==null?void 0:g.decrypt)&&(i.push(g.decrypt),(g==null?void 0:g.push)&&d.push({push:g.push,decrypt:g.decrypt})),C&&C({program:A})}p.length&&await Se(A,{dotsecConfig:n,encryptHandlers:p}),i.length&&await xe(A,{dotsecConfig:n,decryptHandlers:i}),d.length&&await Ve(A,{dotsecConfig:n,handlers:d}),await ke(A,{dotsecConfig:n}),await Re(A,{dotsecConfig:n,decryptHandlers:i}),await A.parse()})();
67
- //# sourceMappingURL=index.js.map
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