@tadnt2003/n8n-nodes-infisical 0.2.0 → 0.2.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,4 +1,4 @@
|
|
|
1
|
-
# n8n-nodes-infisical
|
|
1
|
+
# @tadnt2003/n8n-nodes-infisical
|
|
2
2
|
|
|
3
3
|
An n8n community node for integrating [Infisical](https://infisical.com/) — the open-source secrets management platform — into your n8n workflows.
|
|
4
4
|
|
|
@@ -20,7 +20,7 @@ An n8n community node for integrating [Infisical](https://infisical.com/) — th
|
|
|
20
20
|
|
|
21
21
|
Follow the [community nodes installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n documentation.
|
|
22
22
|
|
|
23
|
-
Package name:
|
|
23
|
+
Package name: `@tadnt2003/n8n-nodes-infisical`
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
@@ -41,12 +41,13 @@ Universal Auth uses a Machine Identity's Client ID and Client Secret to obtain a
|
|
|
41
41
|
|
|
42
42
|
**Credential fields:**
|
|
43
43
|
|
|
44
|
-
| Field | Description |
|
|
45
|
-
| --- | --- |
|
|
46
|
-
| API URL | Base URL of your Infisical API (default: `https://app.infisical.com/api`) |
|
|
47
|
-
| Authentication Type | Select **Universal Auth (Machine Identity)** |
|
|
48
|
-
| Client ID | The Machine Identity's Client ID |
|
|
49
|
-
| Client Secret | The Machine Identity's Client Secret |
|
|
44
|
+
| Field | Required | Description |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| API URL | Yes | Base URL of your Infisical API (default: `https://app.infisical.com/api`) |
|
|
47
|
+
| Authentication Type | Yes | Select **Universal Auth (Machine Identity)** |
|
|
48
|
+
| Client ID | Yes | The Machine Identity's Client ID |
|
|
49
|
+
| Client Secret | Yes | The Machine Identity's Client Secret |
|
|
50
|
+
| Organization Slug | No | Scope the access token to a specific organization. Leave blank to use the organization the machine identity belongs to. To restrict access to a specific project, assign the identity to that project in Organization Settings → Machine Identities → your identity → Project Access. |
|
|
50
51
|
|
|
51
52
|
### Service Token (Legacy)
|
|
52
53
|
|
|
@@ -59,11 +60,11 @@ Service Tokens are deprecated by Infisical and may be removed in future versions
|
|
|
59
60
|
|
|
60
61
|
**Credential fields:**
|
|
61
62
|
|
|
62
|
-
| Field | Description |
|
|
63
|
-
| --- | --- |
|
|
64
|
-
| API URL | Base URL of your Infisical API (default: `https://app.infisical.com/api`) |
|
|
65
|
-
| Authentication Type | Select **Service Token (Legacy)** |
|
|
66
|
-
| Service Token | Your Infisical Service Token |
|
|
63
|
+
| Field | Required | Description |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| API URL | Yes | Base URL of your Infisical API (default: `https://app.infisical.com/api`) |
|
|
66
|
+
| Authentication Type | Yes | Select **Service Token (Legacy)** |
|
|
67
|
+
| Service Token | Yes | Your Infisical Service Token |
|
|
67
68
|
|
|
68
69
|
> For self-hosted Infisical, set API URL to your instance (e.g., `https://infisical.example.com/api`).
|
|
69
70
|
|
|
@@ -75,15 +76,15 @@ Service Tokens are deprecated by Infisical and may be removed in future versions
|
|
|
75
76
|
|
|
76
77
|
All Secret operations require: **Project ID**, **Environment**, **Secret Path** (default: `/`).
|
|
77
78
|
|
|
78
|
-
| Operation | Description | API |
|
|
79
|
-
| --- | --- | --- |
|
|
80
|
-
| **Get** | Fetch a single secret by key | `GET /
|
|
81
|
-
| **Get Many** | List all secrets in a path | `GET /
|
|
82
|
-
| **Create** | Create a single secret | `POST /
|
|
83
|
-
| **Create Many** | Create multiple secrets in one request | `POST /
|
|
84
|
-
| **Update** | Update a single secret | `PATCH
|
|
85
|
-
| **Update Many** | Update multiple secrets in one request | `PATCH /
|
|
86
|
-
| **Delete** | Delete a single secret by key | `DELETE /
|
|
79
|
+
| Operation | Description | Method | API endpoint |
|
|
80
|
+
| --- | --- | --- | --- |
|
|
81
|
+
| **Get** | Fetch a single secret by key | `GET` | `/v4/secrets/{key}` |
|
|
82
|
+
| **Get Many** | List all secrets in a path | `GET` | `/v4/secrets` |
|
|
83
|
+
| **Create** | Create a single secret | `POST` | `/v4/secrets/{key}` |
|
|
84
|
+
| **Create Many** | Create multiple secrets in one request | `POST` | `/v3/secrets/batch/raw` |
|
|
85
|
+
| **Update** | Update a single secret | `PATCH` | `/v4/secrets/{key}` |
|
|
86
|
+
| **Update Many** | Update multiple secrets in one request | `PATCH` | `/v3/secrets/batch/raw` |
|
|
87
|
+
| **Delete** | Delete a single secret by key | `DELETE` | `/v4/secrets/{key}` |
|
|
87
88
|
|
|
88
89
|
#### Get
|
|
89
90
|
|
|
@@ -115,7 +116,7 @@ Per-secret optional fields: Secret Comment, Skip Multiline Encoding
|
|
|
115
116
|
|
|
116
117
|
| Field | Description |
|
|
117
118
|
| --- | --- |
|
|
118
|
-
| Secret Path Override | Use a different path than the top-level Secret Path |
|
|
119
|
+
| Secret Path Override | Use a different path than the top-level Secret Path for this batch |
|
|
119
120
|
|
|
120
121
|
Returns each created secret as a separate output item. If a secret protection policy is active, returns an approval object instead.
|
|
121
122
|
|
|
@@ -146,7 +147,7 @@ Per-secret optional fields: Secret Value, New Secret Name, Secret Comment, Skip
|
|
|
146
147
|
| Field | Description |
|
|
147
148
|
| --- | --- |
|
|
148
149
|
| Mode | `failOnNotFound` (default) — error if secret missing; `upsert` — create if missing; `ignore` — skip missing secrets |
|
|
149
|
-
| Secret Path Override | Use a different path than the top-level Secret Path |
|
|
150
|
+
| Secret Path Override | Use a different path than the top-level Secret Path for this batch |
|
|
150
151
|
|
|
151
152
|
Returns each updated secret as a separate output item.
|
|
152
153
|
|
|
@@ -154,6 +155,8 @@ Returns each updated secret as a separate output item.
|
|
|
154
155
|
|
|
155
156
|
Required: **Secret Key**
|
|
156
157
|
|
|
158
|
+
The Delete request sends `projectId`, `environment`, and `secretPath` in the JSON request body (not as URL query parameters), as required by the v4 API.
|
|
159
|
+
|
|
157
160
|
### Workspace
|
|
158
161
|
|
|
159
162
|
| Operation | Description |
|
|
@@ -162,6 +165,15 @@ Required: **Secret Key**
|
|
|
162
165
|
|
|
163
166
|
---
|
|
164
167
|
|
|
168
|
+
## API behaviour notes
|
|
169
|
+
|
|
170
|
+
- **Single-secret operations** (Get, Get Many, Create, Update, Delete) use **Infisical API v4** (`/api/v4/secrets/…`).
|
|
171
|
+
- **Batch operations** (Create Many, Update Many) use **Infisical API v3** (`/api/v3/secrets/batch/raw`), which is Infisical's current batch endpoint.
|
|
172
|
+
- Single-secret ops pass the project identifier as `projectId` in the request. Batch ops pass it as `workspaceId`, as required by the respective API versions.
|
|
173
|
+
- When a **secret protection policy** is active on the project, create/update/delete endpoints return an approval object (`{ approval: { id, status, … } }`) instead of the secret directly.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
165
177
|
## Usage Examples
|
|
166
178
|
|
|
167
179
|
### Fetch a single secret
|
|
@@ -211,7 +223,7 @@ Required: **Secret Key**
|
|
|
211
223
|
| --- | --- |
|
|
212
224
|
| n8n | v1.0.0+ |
|
|
213
225
|
| Infisical | Cloud and Community Edition |
|
|
214
|
-
| Infisical API |
|
|
226
|
+
| Infisical API | v4 (get, create, update, delete), v3 (batch ops) |
|
|
215
227
|
| n8n Nodes API | v1 |
|
|
216
228
|
|
|
217
229
|
---
|
|
@@ -64,6 +64,19 @@ class InfisicalApi {
|
|
|
64
64
|
required: true,
|
|
65
65
|
description: 'The Client Secret of your Infisical Machine Identity (Universal Auth)',
|
|
66
66
|
},
|
|
67
|
+
{
|
|
68
|
+
displayName: 'Organization Slug',
|
|
69
|
+
name: 'organizationSlug',
|
|
70
|
+
type: 'string',
|
|
71
|
+
displayOptions: {
|
|
72
|
+
show: {
|
|
73
|
+
authType: ['universalAuth'],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
default: '',
|
|
77
|
+
description: 'Optional. Scope the access token to a specific organization. Leave blank to use the organization the machine identity was created in. ' +
|
|
78
|
+
'To restrict this credential to a specific project, assign the machine identity to that project with the appropriate role in Infisical (Organization Settings → Machine Identities → your identity → Project Access).',
|
|
79
|
+
},
|
|
67
80
|
{
|
|
68
81
|
displayName: 'Service Token',
|
|
69
82
|
name: 'apiKey',
|
|
Binary file
|
|
@@ -8,11 +8,18 @@ async function getInfisicalToken(helpers, credentials) {
|
|
|
8
8
|
if (authType === 'universalAuth') {
|
|
9
9
|
const clientId = credentials.clientId;
|
|
10
10
|
const clientSecret = credentials.clientSecret;
|
|
11
|
+
const parts = [
|
|
12
|
+
`clientId=${encodeURIComponent(clientId)}`,
|
|
13
|
+
`clientSecret=${encodeURIComponent(clientSecret)}`,
|
|
14
|
+
];
|
|
15
|
+
if (credentials.organizationSlug) {
|
|
16
|
+
parts.push(`organizationSlug=${encodeURIComponent(credentials.organizationSlug)}`);
|
|
17
|
+
}
|
|
11
18
|
const tokenResponse = await helpers.httpRequest({
|
|
12
19
|
method: 'POST',
|
|
13
20
|
url: `${apiUrl}/v1/auth/universal-auth/login`,
|
|
14
21
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
15
|
-
body:
|
|
22
|
+
body: parts.join('&'),
|
|
16
23
|
});
|
|
17
24
|
return { apiUrl, accessToken: tokenResponse.accessToken };
|
|
18
25
|
}
|
|
@@ -470,13 +477,17 @@ class Infisical {
|
|
|
470
477
|
try {
|
|
471
478
|
let accessToken;
|
|
472
479
|
if (authType === 'universalAuth') {
|
|
480
|
+
const loginForm = {
|
|
481
|
+
clientId: creds.clientId,
|
|
482
|
+
clientSecret: creds.clientSecret,
|
|
483
|
+
};
|
|
484
|
+
if (creds.organizationSlug) {
|
|
485
|
+
loginForm.organizationSlug = creds.organizationSlug;
|
|
486
|
+
}
|
|
473
487
|
const tokenResponse = await this.helpers.request({
|
|
474
488
|
method: 'POST',
|
|
475
489
|
uri: `${apiUrl}/v1/auth/universal-auth/login`,
|
|
476
|
-
form:
|
|
477
|
-
clientId: creds.clientId,
|
|
478
|
-
clientSecret: creds.clientSecret,
|
|
479
|
-
},
|
|
490
|
+
form: loginForm,
|
|
480
491
|
json: true,
|
|
481
492
|
});
|
|
482
493
|
accessToken = tokenResponse.accessToken;
|
|
@@ -530,9 +541,9 @@ class Infisical {
|
|
|
530
541
|
const secretKey = this.getNodeParameter('secretKey', i);
|
|
531
542
|
const response = await this.helpers.httpRequest({
|
|
532
543
|
method: 'GET',
|
|
533
|
-
url: `${apiUrl}/
|
|
544
|
+
url: `${apiUrl}/v4/secrets/${encodeURIComponent(secretKey)}`,
|
|
534
545
|
headers: baseHeaders,
|
|
535
|
-
qs: { workspaceId, environment, secretPath },
|
|
546
|
+
qs: { projectId: workspaceId, environment, secretPath },
|
|
536
547
|
});
|
|
537
548
|
returnData.push({ json: response, pairedItem: { item: i } });
|
|
538
549
|
// ── getAll ────────────────────────────────────────────────────────────
|
|
@@ -540,9 +551,9 @@ class Infisical {
|
|
|
540
551
|
else if (operation === 'getAll') {
|
|
541
552
|
const response = await this.helpers.httpRequest({
|
|
542
553
|
method: 'GET',
|
|
543
|
-
url: `${apiUrl}/
|
|
554
|
+
url: `${apiUrl}/v4/secrets`,
|
|
544
555
|
headers: baseHeaders,
|
|
545
|
-
qs: { workspaceId, environment, secretPath },
|
|
556
|
+
qs: { projectId: workspaceId, environment, secretPath },
|
|
546
557
|
});
|
|
547
558
|
const secrets = response.secrets;
|
|
548
559
|
for (const secret of secrets) {
|
|
@@ -555,9 +566,8 @@ class Infisical {
|
|
|
555
566
|
const secretValue = this.getNodeParameter('secretValue', i);
|
|
556
567
|
const createOptions = this.getNodeParameter('createOptions', i, {});
|
|
557
568
|
const body = {
|
|
558
|
-
workspaceId,
|
|
569
|
+
projectId: workspaceId,
|
|
559
570
|
environment,
|
|
560
|
-
secretName: secretKey,
|
|
561
571
|
secretValue,
|
|
562
572
|
secretPath,
|
|
563
573
|
type: (_a = createOptions.type) !== null && _a !== void 0 ? _a : 'shared',
|
|
@@ -569,7 +579,7 @@ class Infisical {
|
|
|
569
579
|
}
|
|
570
580
|
const response = await this.helpers.httpRequest({
|
|
571
581
|
method: 'POST',
|
|
572
|
-
url: `${apiUrl}/
|
|
582
|
+
url: `${apiUrl}/v4/secrets/${encodeURIComponent(secretKey)}`,
|
|
573
583
|
headers: baseHeaders,
|
|
574
584
|
body: JSON.stringify(body),
|
|
575
585
|
});
|
|
@@ -608,14 +618,19 @@ class Infisical {
|
|
|
608
618
|
}
|
|
609
619
|
else if (operation === 'delete') {
|
|
610
620
|
const secretKey = this.getNodeParameter('secretKey', i);
|
|
621
|
+
const deleteBody = {
|
|
622
|
+
projectId: workspaceId,
|
|
623
|
+
environment,
|
|
624
|
+
secretPath,
|
|
625
|
+
};
|
|
611
626
|
const response = await this.helpers.httpRequest({
|
|
612
627
|
method: 'DELETE',
|
|
613
|
-
url: `${apiUrl}/
|
|
628
|
+
url: `${apiUrl}/v4/secrets/${encodeURIComponent(secretKey)}`,
|
|
614
629
|
headers: baseHeaders,
|
|
615
|
-
|
|
630
|
+
body: JSON.stringify(deleteBody),
|
|
616
631
|
});
|
|
617
632
|
returnData.push({ json: response, pairedItem: { item: i } });
|
|
618
|
-
// ── createMany (
|
|
633
|
+
// ── createMany (v3 batch POST) ────────────────────────────────────────
|
|
619
634
|
}
|
|
620
635
|
else if (operation === 'createMany') {
|
|
621
636
|
const secretsParam = this.getNodeParameter('secrets', i, {});
|
|
@@ -637,14 +652,14 @@ class Infisical {
|
|
|
637
652
|
return s;
|
|
638
653
|
});
|
|
639
654
|
const body = {
|
|
640
|
-
|
|
655
|
+
workspaceId,
|
|
641
656
|
environment,
|
|
642
657
|
secretPath: effectivePath,
|
|
643
658
|
secrets,
|
|
644
659
|
};
|
|
645
660
|
const response = await this.helpers.httpRequest({
|
|
646
661
|
method: 'POST',
|
|
647
|
-
url: `${apiUrl}/
|
|
662
|
+
url: `${apiUrl}/v3/secrets/batch/raw`,
|
|
648
663
|
headers: baseHeaders,
|
|
649
664
|
body: JSON.stringify(body),
|
|
650
665
|
});
|
|
@@ -658,7 +673,7 @@ class Infisical {
|
|
|
658
673
|
// Approval / policy-gated response
|
|
659
674
|
returnData.push({ json: responseData, pairedItem: { item: i } });
|
|
660
675
|
}
|
|
661
|
-
// ── updateMany (
|
|
676
|
+
// ── updateMany (v3 batch PATCH) ───────────────────────────────────────
|
|
662
677
|
}
|
|
663
678
|
else if (operation === 'updateMany') {
|
|
664
679
|
const secretsToUpdateParam = this.getNodeParameter('secretsToUpdate', i, {});
|
|
@@ -683,7 +698,7 @@ class Infisical {
|
|
|
683
698
|
return s;
|
|
684
699
|
});
|
|
685
700
|
const body = {
|
|
686
|
-
|
|
701
|
+
workspaceId,
|
|
687
702
|
environment,
|
|
688
703
|
secretPath: effectivePath,
|
|
689
704
|
secrets,
|
|
@@ -692,7 +707,7 @@ class Infisical {
|
|
|
692
707
|
body.mode = updateManyOptions.mode;
|
|
693
708
|
const response = await this.helpers.httpRequest({
|
|
694
709
|
method: 'PATCH',
|
|
695
|
-
url: `${apiUrl}/
|
|
710
|
+
url: `${apiUrl}/v3/secrets/batch/raw`,
|
|
696
711
|
headers: baseHeaders,
|
|
697
712
|
body: JSON.stringify(body),
|
|
698
713
|
});
|