Merge branch 'bot' into bot

This commit is contained in:
BlackMagiq
2022-12-21 17:11:09 -05:00
committed by GitHub
85 changed files with 2107 additions and 790 deletions
+1 -1
View File
@@ -9,13 +9,13 @@ ENCRYPTION_KEY=replace_with_lengthy_secure_hex
JWT_SIGNUP_SECRET=replace_with_lengthy_secure_hex JWT_SIGNUP_SECRET=replace_with_lengthy_secure_hex
JWT_REFRESH_SECRET=replace_with_lengthy_secure_hex JWT_REFRESH_SECRET=replace_with_lengthy_secure_hex
JWT_AUTH_SECRET=replace_with_lengthy_secure_hex JWT_AUTH_SECRET=replace_with_lengthy_secure_hex
JWT_SERVICE_SECRET=replace_with_lengthy_secure_hex
# JWT lifetime # JWT lifetime
# Optional lifetimes for JWT tokens expressed in seconds or a string # Optional lifetimes for JWT tokens expressed in seconds or a string
# describing a time span (e.g. 60, "2 days", "10h", "7d") # describing a time span (e.g. 60, "2 days", "10h", "7d")
JWT_AUTH_LIFETIME= JWT_AUTH_LIFETIME=
JWT_REFRESH_LIFETIME= JWT_REFRESH_LIFETIME=
JWT_SERVICE_SECRET=
JWT_SIGNUP_LIFETIME= JWT_SIGNUP_LIFETIME=
# Optional lifetimes for OTP expressed in seconds # Optional lifetimes for OTP expressed in seconds
@@ -27,12 +27,3 @@ jobs:
push: true push: true
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
tags: infisical/kubernetes-operator:latest tags: infisical/kubernetes-operator:latest
- uses: actions/setup-go@v2
- name: Upload CRD manifest
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: dist/install-secrets-operator.yaml
tag: ${{ github.ref }}
+1
View File
@@ -81,6 +81,7 @@ nfpms:
- rpm - rpm
- deb - deb
- apk - apk
- archlinux
bindir: /usr/bin bindir: /usr/bin
scoop: scoop:
bucket: bucket:
-7
View File
@@ -1,7 +0,0 @@
{
"semi": true,
"trailingComma": "none",
"singleQuote": true,
"printWidth": 80,
"useTabs": false
}
+19 -12
View File
@@ -27,6 +27,9 @@
<a href="https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g"> <a href="https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g">
<img src="https://img.shields.io/badge/chat-on%20Slack-blueviolet" alt="Slack community channel" /> <img src="https://img.shields.io/badge/chat-on%20Slack-blueviolet" alt="Slack community channel" />
</a> </a>
<a href="https://twitter.com/infisical">
<img src="https://img.shields.io/twitter/follow/infisical?label=Follow" alt="Infisical Twitter" />
</a>
</h4> </h4>
<img src="/img/infisical_github_repo.png" width="100%" alt="Dashboard" /> <img src="/img/infisical_github_repo.png" width="100%" alt="Dashboard" />
@@ -92,12 +95,6 @@ Not sure where to get started? You can:
We're currently in Public Alpha. We're currently in Public Alpha.
## 🚨 Stay Up-to-Date
Infisical officially launched as v.1.0 on November 21st, 2022. However, a lot of new features are coming very quickly. Watch **releases** of this repository to be notified about future updates:
![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true)
## 🔌 Integrations ## 🔌 Integrations
We're currently setting the foundation and building [integrations](https://infisical.com/docs/integrations/overview) so secrets can be synced everywhere. Any help is welcome! :) We're currently setting the foundation and building [integrations](https://infisical.com/docs/integrations/overview) so secrets can be synced everywhere. Any help is welcome! :)
@@ -131,10 +128,14 @@ We're currently setting the foundation and building [integrations](https://infis
</tr> </tr>
<tr> <tr>
<td align="left" valign="middle"> <td align="left" valign="middle">
🔜 Vercel (https://github.com/Infisical/infisical/issues/60) <a href="https://infisical.com/docs/integrations/cloud/vercel?ref=github.com">
✔️ Vercel
</a>
</td> </td>
<td align="left" valign="middle"> <td align="left" valign="middle">
🔜 GitLab CI/CD <a href="https://infisical.com/docs/integrations/platforms/kubernetes?ref=github.com">
✔️ Kubernetes
</a>
</td> </td>
<td align="left" valign="middle"> <td align="left" valign="middle">
🔜 Fly.io 🔜 Fly.io
@@ -156,10 +157,10 @@ We're currently setting the foundation and building [integrations](https://infis
🔜 GCP 🔜 GCP
</td> </td>
<td align="left" valign="middle"> <td align="left" valign="middle">
🔜 Kubernetes 🔜 GitLab CI/CD (https://github.com/Infisical/infisical/issues/134)
</td> </td>
<td align="left" valign="middle"> <td align="left" valign="middle">
🔜 CircleCI 🔜 CircleCI (https://github.com/Infisical/infisical/issues/91)
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -192,7 +193,7 @@ We're currently setting the foundation and building [integrations](https://infis
🔜 Supabase 🔜 Supabase
</td> </td>
<td align="left" valign="middle"> <td align="left" valign="middle">
🔜 Serverless 🔜 Render (https://github.com/Infisical/infisical/issues/132)
</td> </td>
</tr> </tr>
</tbody> </tbody>
@@ -302,6 +303,12 @@ This repo is entirely MIT licensed, with the exception of the `ee` directory whi
Looking to report a security vulnerability? Please don't post about it in GitHub issue. Instead, refer to our [SECURITY.md](./SECURITY.md) file. Looking to report a security vulnerability? Please don't post about it in GitHub issue. Instead, refer to our [SECURITY.md](./SECURITY.md) file.
## 🚨 Stay Up-to-Date
Infisical officially launched as v.1.0 on November 21st, 2022. However, a lot of new features are coming very quickly. Watch **releases** of this repository to be notified about future updates:
![infisical-star-github](https://github.com/Infisical/infisical/blob/main/.github/images/star-infisical.gif?raw=true)
## 🦸 Contributors ## 🦸 Contributors
[//]: contributor-faces [//]: contributor-faces
@@ -310,4 +317,4 @@ Looking to report a security vulnerability? Please don't post about it in GitHub
<!-- prettier-ignore-start --> <!-- prettier-ignore-start -->
<!-- markdownlint-disable --> <!-- markdownlint-disable -->
<a href="https://github.com/dangtony98"><img src="https://avatars.githubusercontent.com/u/25857006?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/mv-turtle"><img src="https://avatars.githubusercontent.com/u/78047717?s=96&v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/maidul98"><img src="https://avatars.githubusercontent.com/u/9300960?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/gangjun06"><img src="https://avatars.githubusercontent.com/u/50910815?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/reginaldbondoc"><img src="https://avatars.githubusercontent.com/u/7693108?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/SH5H"><img src="https://avatars.githubusercontent.com/u/25437192?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/asharonbaltazar"><img src="https://avatars.githubusercontent.com/u/58940073?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/edgarrmondragon"><img src="https://avatars.githubusercontent.com/u/16805946?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/arjunyel"><img src="https://avatars.githubusercontent.com/u/11153289?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/LemmyMwaura"><img src="https://avatars.githubusercontent.com/u/20738858?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/adrianmarinwork"><img src="https://avatars.githubusercontent.com/u/118568289?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/hanywang2"><img src="https://avatars.githubusercontent.com/u/44352119?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/tobias-mintlify"><img src="https://avatars.githubusercontent.com/u/110702161?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/0xflotus"><img src="https://avatars.githubusercontent.com/u/26602940?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/wanjohiryan"><img src="https://avatars.githubusercontent.com/u/71614375?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/dangtony98"><img src="https://avatars.githubusercontent.com/u/25857006?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/mv-turtle"><img src="https://avatars.githubusercontent.com/u/78047717?s=96&v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/maidul98"><img src="https://avatars.githubusercontent.com/u/9300960?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/gangjun06"><img src="https://avatars.githubusercontent.com/u/50910815?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/reginaldbondoc"><img src="https://avatars.githubusercontent.com/u/7693108?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/SH5H"><img src="https://avatars.githubusercontent.com/u/25437192?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/asharonbaltazar"><img src="https://avatars.githubusercontent.com/u/58940073?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/edgarrmondragon"><img src="https://avatars.githubusercontent.com/u/16805946?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/arjunyel"><img src="https://avatars.githubusercontent.com/u/11153289?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/LemmyMwaura"><img src="https://avatars.githubusercontent.com/u/20738858?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/Zamion101"><img src="https://avatars.githubusercontent.com/u/8071263?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/adrianmarinwork"><img src="https://avatars.githubusercontent.com/u/118568289?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/hanywang2"><img src="https://avatars.githubusercontent.com/u/44352119?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/tobias-mintlify"><img src="https://avatars.githubusercontent.com/u/110702161?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/0xflotus"><img src="https://avatars.githubusercontent.com/u/26602940?v=4" width="50" height="50" alt=""/></a> <a href="https://github.com/wanjohiryan"><img src="https://avatars.githubusercontent.com/u/71614375?v=4" width="50" height="50" alt=""/></a>
+2 -3
View File
@@ -1,11 +1,10 @@
{ {
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier"], "plugins": ["@typescript-eslint"],
"extends": [ "extends": [
"eslint:recommended", "eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended"
"prettier"
], ],
"rules": { "rules": {
"no-console": 2 "no-console": 2
+2 -2
View File
@@ -4,12 +4,12 @@ WORKDIR /app
COPY package.json package-lock.json ./ COPY package.json package-lock.json ./
RUN npm ci --only-production RUN npm ci --only-production --ignore-scripts
COPY . . COPY . .
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \ HEALTHCHECK --interval=10s --timeout=3s --start-period=10s \
CMD node healthcheck.js CMD node healthcheck.js
CMD ["npm", "run", "start"] CMD ["npm", "run", "start"]
+7 -123
View File
@@ -52,13 +52,10 @@
"@typescript-eslint/eslint-plugin": "^5.40.1", "@typescript-eslint/eslint-plugin": "^5.40.1",
"@typescript-eslint/parser": "^5.40.1", "@typescript-eslint/parser": "^5.40.1",
"eslint": "^8.26.0", "eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"install": "^0.13.0", "install": "^0.13.0",
"jest": "^29.3.1", "jest": "^29.3.1",
"nodemon": "^2.0.19", "nodemon": "^2.0.19",
"npm": "^8.19.3", "npm": "^8.19.3",
"prettier": "^2.7.1",
"ts-node": "^10.9.1" "ts-node": "^10.9.1"
} }
}, },
@@ -3073,12 +3070,6 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==",
"dev": true
},
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
@@ -3930,6 +3921,7 @@
"dependencies": { "dependencies": {
"anymatch": "~3.1.2", "anymatch": "~3.1.2",
"braces": "~3.0.2", "braces": "~3.0.2",
"fsevents": "~2.3.2",
"glob-parent": "~5.1.2", "glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0", "is-binary-path": "~2.1.0",
"is-glob": "~4.0.1", "is-glob": "~4.0.1",
@@ -4431,39 +4423,6 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint-config-prettier": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
"integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
"dev": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
"peerDependencies": {
"eslint": ">=7.0.0"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
"integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
"dev": true,
"dependencies": {
"prettier-linter-helpers": "^1.0.0"
},
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"eslint": ">=7.28.0",
"prettier": ">=2.0.0"
},
"peerDependenciesMeta": {
"eslint-config-prettier": {
"optional": true
}
}
},
"node_modules/eslint-scope": { "node_modules/eslint-scope": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -4781,12 +4740,6 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true "dev": true
}, },
"node_modules/fast-diff": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
"dev": true
},
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.2.12", "version": "3.2.12",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
@@ -5180,6 +5133,7 @@
"minimist": "^1.2.5", "minimist": "^1.2.5",
"neo-async": "^2.6.0", "neo-async": "^2.6.0",
"source-map": "^0.6.1", "source-map": "^0.6.1",
"uglify-js": "^3.1.4",
"wordwrap": "^1.0.0" "wordwrap": "^1.0.0"
}, },
"bin": { "bin": {
@@ -5837,6 +5791,7 @@
"@types/node": "*", "@types/node": "*",
"anymatch": "^3.0.3", "anymatch": "^3.0.3",
"fb-watchman": "^2.0.0", "fb-watchman": "^2.0.0",
"fsevents": "^2.3.2",
"graceful-fs": "^4.2.9", "graceful-fs": "^4.2.9",
"jest-regex-util": "^29.2.0", "jest-regex-util": "^29.2.0",
"jest-util": "^29.3.1", "jest-util": "^29.3.1",
@@ -6053,7 +6008,6 @@
"@jest/transform": "^29.3.1", "@jest/transform": "^29.3.1",
"@jest/types": "^29.3.1", "@jest/types": "^29.3.1",
"@types/babel__traverse": "^7.0.6", "@types/babel__traverse": "^7.0.6",
"@types/prettier": "^2.1.5",
"babel-preset-current-node-syntax": "^1.0.0", "babel-preset-current-node-syntax": "^1.0.0",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"expect": "^29.3.1", "expect": "^29.3.1",
@@ -6641,9 +6595,11 @@
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.11.0.tgz", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.11.0.tgz",
"integrity": "sha512-9l9n4Nk2BYZzljW3vHah3Z0rfS5npKw6ktnkmFgTcnzaXH1DRm3pDl6VMHu84EVb1lzmSaJC4OzWZqTkB5i2wg==", "integrity": "sha512-9l9n4Nk2BYZzljW3vHah3Z0rfS5npKw6ktnkmFgTcnzaXH1DRm3pDl6VMHu84EVb1lzmSaJC4OzWZqTkB5i2wg==",
"dependencies": { "dependencies": {
"@aws-sdk/credential-providers": "^3.186.0",
"bson": "^4.7.0", "bson": "^4.7.0",
"denque": "^2.1.0", "denque": "^2.1.0",
"mongodb-connection-string-url": "^2.5.4", "mongodb-connection-string-url": "^2.5.4",
"saslprep": "^1.0.3",
"socks": "^2.7.1" "socks": "^2.7.1"
}, },
"engines": { "engines": {
@@ -6873,9 +6829,6 @@
}, },
"bin": { "bin": {
"nopt": "bin/nopt.js" "nopt": "bin/nopt.js"
},
"engines": {
"node": "*"
} }
}, },
"node_modules/normalize-path": { "node_modules/normalize-path": {
@@ -7729,6 +7682,7 @@
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@colors/colors": "1.5.0",
"string-width": "^4.2.0" "string-width": "^4.2.0"
}, },
"engines": { "engines": {
@@ -8524,6 +8478,7 @@
"inBundle": true, "inBundle": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"encoding": "^0.1.13",
"minipass": "^3.1.6", "minipass": "^3.1.6",
"minipass-sized": "^1.0.3", "minipass-sized": "^1.0.3",
"minizlib": "^2.1.2" "minizlib": "^2.1.2"
@@ -9897,33 +9852,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-linter-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
"dependencies": {
"fast-diff": "^1.1.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/pretty-format": { "node_modules/pretty-format": {
"version": "29.3.1", "version": "29.3.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz",
@@ -13854,12 +13782,6 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==",
"dev": true
},
"@types/qs": { "@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
@@ -14860,22 +14782,6 @@
} }
} }
}, },
"eslint-config-prettier": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
"integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
"dev": true,
"requires": {}
},
"eslint-plugin-prettier": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
"integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
"dev": true,
"requires": {
"prettier-linter-helpers": "^1.0.0"
}
},
"eslint-scope": { "eslint-scope": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -15098,12 +15004,6 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true "dev": true
}, },
"fast-diff": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
"dev": true
},
"fast-glob": { "fast-glob": {
"version": "3.2.12", "version": "3.2.12",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
@@ -16033,7 +15933,6 @@
"@jest/transform": "^29.3.1", "@jest/transform": "^29.3.1",
"@jest/types": "^29.3.1", "@jest/types": "^29.3.1",
"@types/babel__traverse": "^7.0.6", "@types/babel__traverse": "^7.0.6",
"@types/prettier": "^2.1.5",
"babel-preset-current-node-syntax": "^1.0.0", "babel-preset-current-node-syntax": "^1.0.0",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"expect": "^29.3.1", "expect": "^29.3.1",
@@ -18718,21 +18617,6 @@
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true "dev": true
}, },
"prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true
},
"prettier-linter-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
"requires": {
"fast-diff": "^1.1.2"
}
},
"pretty-format": { "pretty-format": {
"version": "29.3.1", "version": "29.3.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz",
+2 -5
View File
@@ -34,12 +34,12 @@
"version": "1.0.0", "version": "1.0.0",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
"prepare": "cd .. && npm install",
"start": "npm run build && node build/index.js", "start": "npm run build && node build/index.js",
"dev": "nodemon", "dev": "nodemon",
"build": "rimraf ./build && tsc && cp -R ./src/templates ./src/json ./build", "build": "rimraf ./build && tsc && cp -R ./src/templates ./build",
"lint": "eslint . --ext .ts", "lint": "eslint . --ext .ts",
"lint-and-fix": "eslint . --ext .ts --fix", "lint-and-fix": "eslint . --ext .ts --fix",
"prettier-format": "prettier --config .prettierrc 'src/**/*.ts' --write",
"lint-staged": "lint-staged" "lint-staged": "lint-staged"
}, },
"repository": { "repository": {
@@ -66,13 +66,10 @@
"@typescript-eslint/eslint-plugin": "^5.40.1", "@typescript-eslint/eslint-plugin": "^5.40.1",
"@typescript-eslint/parser": "^5.40.1", "@typescript-eslint/parser": "^5.40.1",
"eslint": "^8.26.0", "eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"install": "^0.13.0", "install": "^0.13.0",
"jest": "^29.3.1", "jest": "^29.3.1",
"nodemon": "^2.0.19", "nodemon": "^2.0.19",
"npm": "^8.19.3", "npm": "^8.19.3",
"prettier": "^2.7.1",
"ts-node": "^10.9.1" "ts-node": "^10.9.1"
} }
} }
+3 -3
View File
@@ -18,9 +18,8 @@ const CLIENT_ID_GITHUB =
process.env.CLIENT_ID_GITHUB! || 'e787fc24bcec43ecd5d5'; process.env.CLIENT_ID_GITHUB! || 'e787fc24bcec43ecd5d5';
const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!; const CLIENT_SECRET_VERCEL = process.env.CLIENT_SECRET_VERCEL!;
const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!; const CLIENT_SECRET_NETLIFY = process.env.CLIENT_SECRET_NETLIFY!;
const CLIENT_SECRET_GITHUB = const CLIENT_SECRET_GITHUB = process.env.CLIENT_SECRET_GITHUB! || '407f32da788f63559abd662c6de08bb2911ca8ae';
process.env.CLIENT_SECRET_GITHUB! || const CLIENT_SLUG_VERCEL= process.env.CLIENT_SLUG_VERCEL!;
'407f32da788f63559abd662c6de08bb2911ca8ae';
const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com'; const POSTHOG_HOST = process.env.POSTHOG_HOST! || 'https://app.posthog.com';
const POSTHOG_PROJECT_API_KEY = const POSTHOG_PROJECT_API_KEY =
process.env.POSTHOG_PROJECT_API_KEY! || process.env.POSTHOG_PROJECT_API_KEY! ||
@@ -63,6 +62,7 @@ export {
CLIENT_SECRET_VERCEL, CLIENT_SECRET_VERCEL,
CLIENT_SECRET_NETLIFY, CLIENT_SECRET_NETLIFY,
CLIENT_SECRET_GITHUB, CLIENT_SECRET_GITHUB,
CLIENT_SLUG_VERCEL,
POSTHOG_HOST, POSTHOG_HOST,
POSTHOG_PROJECT_API_KEY, POSTHOG_PROJECT_API_KEY,
PRIVATE_KEY, PRIVATE_KEY,
+3 -3
View File
@@ -53,12 +53,12 @@ const handleOAuthExchangeHelper = async ({
if (!bot) throw new Error('Bot must be enabled for OAuth2 code-token exchange'); if (!bot) throw new Error('Bot must be enabled for OAuth2 code-token exchange');
// exchange code for access and refresh tokens // exchange code for access and refresh tokens
let res = await exchangeCode({ const res = await exchangeCode({
integration, integration,
code code
}); });
let update: Update = { const update: Update = {
workspace: workspaceId, workspace: workspaceId,
integration integration
} }
@@ -138,7 +138,7 @@ const syncIntegrationsHelper = async ({
// to that integration // to that integration
for await (const integration of integrations) { for await (const integration of integrations) {
// get workspace, environment (shared) secrets // get workspace, environment (shared) secrets
const secrets = await BotService.getSecrets({ const secrets = await BotService.getSecrets({ // issue here?
workspaceId: integration.workspace.toString(), workspaceId: integration.workspace.toString(),
environment: integration.environment environment: integration.environment
}); });
+308 -271
View File
@@ -64,14 +64,13 @@ const syncSecrets = async ({
}); });
break; break;
case INTEGRATION_GITHUB: case INTEGRATION_GITHUB:
await syncSecretsNetlify({ await syncSecretsGitHub({
integration, integration,
integrationAuth, integrationAuth,
secrets, secrets,
accessToken accessToken
}); });
break; break;
}
} catch (err) { } catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
Sentry.captureException(err); Sentry.captureException(err);
@@ -137,157 +136,149 @@ const syncSecretsHeroku = async ({
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
*/ */
const syncSecretsVercel = async ({ const syncSecretsVercel = async ({
integration, integration,
secrets, secrets,
accessToken accessToken
}: { }: {
integration: IIntegration; integration: IIntegration,
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
interface VercelSecret {
id?: string;
type: string;
key: string;
value: string;
target: string[];
}
try { interface VercelSecret {
// Get all (decrypted) secrets back from Vercel in id?: string;
// decrypted format type: string;
const params = new URLSearchParams({ key: string;
decrypt: 'true' value: string;
}); target: string[];
}
const res = ( try {
await Promise.all( // Get all (decrypted) secrets back from Vercel in
( // decrypted format
await axios.get( const params = new URLSearchParams({
decrypt: "true"
});
const res = (await Promise.all((await axios.get(
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env`, `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env`,
{ {
params, params,
headers: { headers: {
Authorization: `Bearer ${accessToken}` Authorization: `Bearer ${accessToken}`
} }
} }
) ))
).data.envs .data
.filter((secret: VercelSecret) => .envs
secret.target.includes(integration.target) .filter((secret: VercelSecret) => secret.target.includes(integration.target))
) .map(async (secret: VercelSecret) => (await axios.get(
.map( `${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`,
async (secret: VercelSecret) => {
(
await axios.get(
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`,
{
headers: { headers: {
Authorization: `Bearer ${accessToken}` Authorization: `Bearer ${accessToken}`
} }
}
)
).data
)
)
).reduce(
(obj: any, secret: any) => ({
...obj,
[secret.key]: secret
}),
{}
);
const updateSecrets: VercelSecret[] = []; }
const deleteSecrets: VercelSecret[] = []; )).data)
const newSecrets: VercelSecret[] = []; )).reduce((obj: any, secret: any) => ({
...obj,
[secret.key]: secret
}), {});
// Identify secrets to create const updateSecrets: VercelSecret[] = [];
Object.keys(secrets).map((key) => { const deleteSecrets: VercelSecret[] = [];
if (!(key in res)) { const newSecrets: VercelSecret[] = [];
// case: secret has been created
newSecrets.push({
key: key,
value: secrets[key],
type: 'encrypted',
target: [integration.target]
});
}
});
// Identify secrets to update and delete // Identify secrets to create
Object.keys(res).map((key) => { Object.keys(secrets).map((key) => {
if (key in secrets) { if (!(key in res)) {
if (res[key].value !== secrets[key]) { // case: secret has been created
// case: secret value has changed newSecrets.push({
updateSecrets.push({ key: key,
id: res[key].id, value: secrets[key],
key: key, type: 'encrypted',
value: secrets[key], target: [integration.target]
type: 'encrypted', });
target: [integration.target]
});
}
} else {
// case: secret has been deleted
deleteSecrets.push({
id: res[key].id,
key: key,
value: res[key].value,
type: 'encrypted',
target: [integration.target]
});
}
});
// Sync/push new secrets
if (newSecrets.length > 0) {
await axios.post(
`${INTEGRATION_VERCEL_API_URL}/v10/projects/${integration.app}/env`,
newSecrets,
{
headers: {
Authorization: `Bearer ${accessToken}`
}
}
);
}
// Sync/push updated secrets
if (updateSecrets.length > 0) {
updateSecrets.forEach(async (secret: VercelSecret) => {
const { id, ...updatedSecret } = secret;
await axios.patch(
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`,
updatedSecret,
{
headers: {
Authorization: `Bearer ${accessToken}`
} }
} });
);
});
}
// Delete secrets // Identify secrets to update and delete
if (deleteSecrets.length > 0) { Object.keys(res).map((key) => {
deleteSecrets.forEach(async (secret: VercelSecret) => { if (key in secrets) {
await axios.delete( if (res[key].value !== secrets[key]) {
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`, // case: secret value has changed
{ updateSecrets.push({
headers: { id: res[key].id,
Authorization: `Bearer ${accessToken}` key: key,
value: secrets[key],
type: 'encrypted',
target: [integration.target]
});
}
} else {
// case: secret has been deleted
deleteSecrets.push({
id: res[key].id,
key: key,
value: res[key].value,
type: 'encrypted',
target: [integration.target],
});
} }
} });
);
}); // Sync/push new secrets
if (newSecrets.length > 0) {
await axios.post(
`${INTEGRATION_VERCEL_API_URL}/v10/projects/${integration.app}/env`,
newSecrets,
{
headers: {
Authorization: `Bearer ${accessToken}`
}
}
);
}
// Sync/push updated secrets
if (updateSecrets.length > 0) {
updateSecrets.forEach(async (secret: VercelSecret) => {
const {
id,
...updatedSecret
} = secret;
await axios.patch(
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`,
updatedSecret,
{
headers: {
Authorization: `Bearer ${accessToken}`
}
}
);
});
}
// Delete secrets
if (deleteSecrets.length > 0) {
deleteSecrets.forEach(async (secret: VercelSecret) => {
await axios.delete(
`${INTEGRATION_VERCEL_API_URL}/v9/projects/${integration.app}/env/${secret.id}`,
{
headers: {
Authorization: `Bearer ${accessToken}`
}
}
);
});
}
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to Vercel');
} }
} catch (err) { }
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to Vercel');
}
};
/** /**
* Sync/push [secrets] to Netlify site [app] * Sync/push [secrets] to Netlify site [app]
@@ -297,165 +288,211 @@ const syncSecretsVercel = async ({
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
*/ */
const syncSecretsNetlify = async ({ const syncSecretsNetlify = async ({
integration, integration,
integrationAuth, integrationAuth,
secrets, secrets,
accessToken accessToken
}: { }: {
integration: IIntegration; integration: IIntegration;
integrationAuth: IIntegrationAuth; integrationAuth: IIntegrationAuth;
secrets: any; secrets: any;
accessToken: string; accessToken: string;
}) => { }) => {
try { try {
const getParams = new URLSearchParams({
context_name: integration.context,
site_id: integration.siteId
});
const res = ( interface NetlifyValue {
await axios.get( id?: string;
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`, context: string; // 'dev' | 'branch-deploy' | 'deploy-preview' | 'production',
{ value: string;
params: getParams,
headers: {
Authorization: `Bearer ${accessToken}`
}
} }
)
).data.reduce(
(obj: any, secret: any) => ({
...obj,
[secret.key]: secret.values[0].value
}),
{}
);
interface UpdateNetlifySecret { interface NetlifySecret {
key: string; key: string;
context: string; values: NetlifyValue[];
value: string; }
}
interface DeleteNetlifySecret { interface NetlifySecretsRes {
key: string; [index: string]: NetlifySecret;
} }
interface NewNetlifySecretValue { const getParams = new URLSearchParams({
value: string; context_name: 'all', // integration.context or all
context: string; site_id: integration.siteId
} });
interface NewNetlifySecret { const res = (await axios.get(
key: string; `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`,
values: NewNetlifySecretValue[];
}
const updateSecrets: UpdateNetlifySecret[] = [];
const deleteSecrets: DeleteNetlifySecret[] = [];
const newSecrets: NewNetlifySecret[] = [];
// Identify secrets to create
Object.keys(secrets).map((key) => {
if (!(key in res)) {
// case: secret has been created
newSecrets.push({
key: key,
values: [
{ {
value: secrets[key], // include id? params: getParams,
context: integration.context headers: {
Authorization: `Bearer ${accessToken}`
}
}
))
.data
.reduce((obj: any, secret: any) => ({
...obj,
[secret.key]: secret
}), {});
const newSecrets: NetlifySecret[] = []; // createEnvVars
const deleteSecrets: string[] = []; // deleteEnvVar
const deleteSecretValues: NetlifySecret[] = []; // deleteEnvVarValue
const updateSecrets: NetlifySecret[] = []; // setEnvVarValue
// identify secrets to create and update
Object.keys(secrets).map((key) => {
if (!(key in res)) {
// case: Infisical secret does not exist in Netlify -> create secret
newSecrets.push({
key,
values: [{
value: secrets[key],
context: integration.context
}]
});
} else {
// case: Infisical secret exists in Netlify
const contexts = res[key].values
.reduce((obj: any, value: NetlifyValue) => ({
...obj,
[value.context]: value
}), {});
if (integration.context in contexts) {
// case: Netlify secret value exists in integration context
if (secrets[key] !== contexts[integration.context].value) {
// case: Infisical and Netlify secret values are different
// -> update Netlify secret context and value
updateSecrets.push({
key,
values: [{
context: integration.context,
value: secrets[key]
}]
});
}
} else {
// case: Netlify secret value does not exist in integration context
// -> add the new Netlify secret context and value
updateSecrets.push({
key,
values: [{
context: integration.context,
value: secrets[key]
}]
});
}
}
})
// identify secrets to delete
// TODO: revise (patch case where 1 context was deleted but others still there
Object.keys(res).map((key) => {
// loop through each key's context
if (!(key in secrets)) {
// case: Netlify secret does not exist in Infisical
const numberOfValues = res[key].values.length;
res[key].values.forEach((value: NetlifyValue) => {
if (value.context === integration.context) {
if (numberOfValues <= 1) {
// case: Netlify secret value has less than 1 context -> delete secret
deleteSecrets.push(key);
} else {
// case: Netlify secret value has more than 1 context -> delete secret value context
deleteSecretValues.push({
key,
values: [{
id: value.id,
context: integration.context,
value: value.value
}]
});
}
}
});
} }
]
}); });
}
});
// Identify secrets to update and delete const syncParams = new URLSearchParams({
Object.keys(res).map((key) => { site_id: integration.siteId
if (key in secrets) {
if (res[key] !== secrets[key]) {
// case: secret value has changed
updateSecrets.push({
key: key,
context: integration.context,
value: secrets[key]
});
}
} else {
// case: secret has been deleted
deleteSecrets.push({
key
}); });
}
});
const syncParams = new URLSearchParams({ if (newSecrets.length > 0) {
site_id: integration.siteId await axios.post(
}); `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`,
newSecrets,
// Sync/push new secrets {
if (newSecrets.length > 0) { params: syncParams,
await axios.post( headers: {
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`, Authorization: `Bearer ${accessToken}`
newSecrets, }
{ }
params: syncParams, );
headers: {
Authorization: `Bearer ${accessToken}`
}
} }
);
}
// Sync/push updated secrets if (updateSecrets.length > 0) {
if (updateSecrets.length > 0) { updateSecrets.forEach(async (secret: NetlifySecret) => {
updateSecrets.forEach(async (secret: UpdateNetlifySecret) => { await axios.patch(
await axios.patch( `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`,
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`, {
{ context: secret.values[0].context,
context: secret.context, value: secret.values[0].value
value: secret.value },
}, {
{ params: syncParams,
params: syncParams, headers: {
headers: { Authorization: `Bearer ${accessToken}`
Authorization: `Bearer ${accessToken}` }
} }
} );
); });
}); }
}
// Delete secrets if (deleteSecrets.length > 0) {
if (deleteSecrets.length > 0) { deleteSecrets.forEach(async (key: string) => {
deleteSecrets.forEach(async (secret: DeleteNetlifySecret) => { await axios.delete(
await axios.delete( `${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`,
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`, {
{ params: syncParams,
params: syncParams, headers: {
headers: { Authorization: `Bearer ${accessToken}`
Authorization: `Bearer ${accessToken}` }
} }
} );
); });
}); }
if (deleteSecretValues.length > 0) {
deleteSecretValues.forEach(async (secret: NetlifySecret) => {
await axios.delete(
`${INTEGRATION_NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`,
{
params: syncParams,
headers: {
Authorization: `Bearer ${accessToken}`
}
}
);
});
}
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to Heroku');
} }
} catch (err) { }
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to sync secrets to Heroku');
}
};
/** /**
* Sync/push [secrets] to Github site [app] * Sync/push [secrets] to GitHub site [app]
* @param {Object} obj * @param {Object} obj
* @param {IIntegration} obj.integration - integration details * @param {IIntegration} obj.integration - integration details
* @param {IIntegrationAuth} obj.integrationAuth - integration auth details * @param {IIntegrationAuth} obj.integrationAuth - integration auth details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
*/ */
const syncSecretsGithub = async ({ const syncSecretsGitHub = async ({
integration, integration,
integrationAuth, integrationAuth,
secrets, secrets,
-4
View File
@@ -27,7 +27,6 @@ router.post(
passwordController.changePassword passwordController.changePassword
); );
// NEW
router.post( router.post(
'/email/password-reset', '/email/password-reset',
passwordLimiter, passwordLimiter,
@@ -36,7 +35,6 @@ router.post(
passwordController.emailPasswordReset passwordController.emailPasswordReset
); );
// NEW
router.post( router.post(
'/email/password-reset-verify', '/email/password-reset-verify',
passwordLimiter, passwordLimiter,
@@ -46,7 +44,6 @@ router.post(
passwordController.emailPasswordResetVerify passwordController.emailPasswordResetVerify
); );
// NEW
router.get( router.get(
'/backup-private-key', '/backup-private-key',
passwordLimiter, passwordLimiter,
@@ -68,7 +65,6 @@ router.post(
passwordController.createBackupPrivateKey passwordController.createBackupPrivateKey
); );
// NEW
router.post( router.post(
'/password-reset', '/password-reset',
requireSignupAuth, requireSignupAuth,
+9
View File
@@ -1,6 +1,7 @@
import nacl from 'tweetnacl'; import nacl from 'tweetnacl';
import util from 'tweetnacl-util'; import util from 'tweetnacl-util';
import AesGCM from './aes-gcm'; import AesGCM from './aes-gcm';
import * as Sentry from '@sentry/node';
/** /**
* Return new base64, NaCl, public-private key pair. * Return new base64, NaCl, public-private key pair.
@@ -47,6 +48,8 @@ const encryptAsymmetric = ({
util.decodeBase64(privateKey) util.decodeBase64(privateKey)
); );
} catch (err) { } catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to perform asymmetric encryption'); throw new Error('Failed to perform asymmetric encryption');
} }
@@ -86,6 +89,8 @@ const decryptAsymmetric = ({
util.decodeBase64(privateKey) util.decodeBase64(privateKey)
); );
} catch (err) { } catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to perform asymmetric decryption'); throw new Error('Failed to perform asymmetric decryption');
} }
@@ -112,6 +117,8 @@ const encryptSymmetric = ({
iv = obj.iv; iv = obj.iv;
tag = obj.tag; tag = obj.tag;
} catch (err) { } catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to perform symmetric encryption'); throw new Error('Failed to perform symmetric encryption');
} }
@@ -147,6 +154,8 @@ const decryptSymmetric = ({
try { try {
plaintext = AesGCM.decrypt(ciphertext, iv, tag, key); plaintext = AesGCM.decrypt(ciphertext, iv, tag, key);
} catch (err) { } catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to perform symmetric decryption'); throw new Error('Failed to perform symmetric decryption');
} }
+3 -1
View File
@@ -1,6 +1,7 @@
import { import {
CLIENT_ID_HEROKU, CLIENT_ID_HEROKU,
CLIENT_ID_NETLIFY CLIENT_ID_NETLIFY,
CLIENT_SLUG_VERCEL
} from '../config'; } from '../config';
// integrations // integrations
@@ -49,6 +50,7 @@ const INTEGRATION_OPTIONS = [
isAvailable: true, isAvailable: true,
type: 'vercel', type: 'vercel',
clientId: '', clientId: '',
clientSlug: CLIENT_SLUG_VERCEL,
docsLink: '' docsLink: ''
}, },
{ {
+83 -14
View File
@@ -8,6 +8,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
"runtime"
"strings" "strings"
"syscall" "syscall"
@@ -19,12 +20,38 @@ import (
// runCmd represents the run command // runCmd represents the run command
var runCmd = &cobra.Command{ var runCmd = &cobra.Command{
Example: `
infisical run --env=dev -- npm run dev
infisical run --command "first-command && second-command; more-commands..."
`,
Use: "run [any infisical run command flags] -- [your application start command]", Use: "run [any infisical run command flags] -- [your application start command]",
Short: "Used to inject environments variables into your application process", Short: "Used to inject environments variables into your application process",
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
Example: "infisical run --env=prod -- npm run dev",
Args: cobra.MinimumNArgs(1),
PreRun: toggleDebug, PreRun: toggleDebug,
Args: func(cmd *cobra.Command, args []string) error {
// Check if the --command flag has been set
commandFlagSet := cmd.Flags().Changed("command")
// If the --command flag has been set, check if a value was provided
if commandFlagSet {
command := cmd.Flag("command").Value.String()
if command == "" {
return fmt.Errorf("you need to provide a command after the flag --command")
}
// If the --command flag has been set, args should not be provided
if len(args) > 0 {
return fmt.Errorf("you cannot set any arguments after --command flag. --command only takes a string command")
}
} else {
// If the --command flag has not been set, at least one arg should be provided
if len(args) == 0 {
return fmt.Errorf("at least one argument is required after the run command, received %d", len(args))
}
}
return nil
},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
envName, err := cmd.Flags().GetString("env") envName, err := cmd.Flags().GetString("env")
if err != nil { if err != nil {
@@ -54,10 +81,23 @@ var runCmd = &cobra.Command{
} }
if shouldExpandSecrets { if shouldExpandSecrets {
secretsWithSubstitutions := util.SubstituteSecrets(secrets) secrets = util.SubstituteSecrets(secrets)
execCmd(args[0], args[1:], secretsWithSubstitutions) }
if cmd.Flags().Changed("command") {
command := cmd.Flag("command").Value.String()
err = executeMultipleCommandWithEnvs(command, secrets)
if err != nil {
log.Errorf("Something went wrong when executing your command [error=%s]", err)
return
}
} else { } else {
execCmd(args[0], args[1:], secrets) err = executeSingleCommandWithEnvs(args, secrets)
if err != nil {
log.Errorf("Something went wrong when executing your command [error=%s]", err)
return
}
return
} }
}, },
@@ -68,22 +108,51 @@ func init() {
runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from") runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
runCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from") runCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from")
runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets") runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
runCmd.Flags().StringP("command", "c", "", "chained commands to execute (e.g. \"npm install && npm run dev; echo ...\")")
} }
// Credit: inspired by AWS Valut // Will execute a single command and pass in the given secrets into the process
func execCmd(command string, args []string, envs []models.SingleEnvironmentVariable) error { func executeSingleCommandWithEnvs(args []string, secrets []models.SingleEnvironmentVariable) error {
numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(envs)) command := args[0]
argsForCommand := args[1:]
numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets))
log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected) log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected)
log.Debugf("executing command: %s %s \n", command, strings.Join(args, " ")) log.Debugf("executing command: %s %s \n", command, strings.Join(argsForCommand, " "))
log.Debugln("Secrets injected:", envs) log.Debugln("Secrets injected:", secrets)
cmd := exec.Command(command, args...) cmd := exec.Command(command, argsForCommand...)
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
cmd.Env = getAllEnvs(envs) cmd.Env = getAllEnvs(secrets)
return execCmd(cmd)
}
func executeMultipleCommandWithEnvs(fullCommand string, secrets []models.SingleEnvironmentVariable) error {
shell := [2]string{"sh", "-c"}
if runtime.GOOS == "windows" {
shell = [2]string{"cmd", "/C"}
} else {
shell[0] = os.Getenv("SHELL")
}
cmd := exec.Command(shell[0], shell[1], fullCommand)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = getAllEnvs(secrets)
numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets))
log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected)
log.Debugf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand)
log.Debugln("Secrets injected:", secrets)
return execCmd(cmd)
}
// Credit: inspired by AWS Valut
func execCmd(cmd *exec.Cmd) error {
sigChannel := make(chan os.Signal, 1) sigChannel := make(chan os.Signal, 1)
signal.Notify(sigChannel) signal.Notify(sigChannel)
@@ -100,7 +169,7 @@ func execCmd(command string, args []string, envs []models.SingleEnvironmentVaria
if err := cmd.Wait(); err != nil { if err := cmd.Wait(); err != nil {
_ = cmd.Process.Signal(os.Kill) _ = cmd.Process.Signal(os.Kill)
return fmt.Errorf("Failed to wait for command termination: %v", err) return fmt.Errorf("failed to wait for command termination: %v", err)
} }
waitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus) waitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus)
+3
View File
@@ -30,4 +30,7 @@ infisical export --format=csv > secrets.csv
# Export variables to a JSON file # Export variables to a JSON file
infisical export --format=json > secrets.json infisical export --format=json > secrets.json
# Export variables to a YAML file
infisical export --format=yaml > secrets.yaml
``` ```
+21 -4
View File
@@ -2,9 +2,25 @@
title: "infisical run" title: "infisical run"
--- ---
```bash <Tabs>
infisical run [options] -- [your application start command] <Tab title="Single command">
``` ```bash
infisical run [options] -- [your application start command]
# Example
infisical run [options] -- npm run dev
```
</Tab>
<Tab title="Chained commands">
```bash
infisical run [options] --command [string command]
# Example
infisical run [options] --command "npm run bootstrap && npm run dev start; other-bash-command"
```
</Tab>
</Tabs>
## Description ## Description
@@ -15,5 +31,6 @@ Inject environment variables from the platform into an application process.
| Option | Description | Default value | | Option | Description | Default value |
| -------------- | ----------------------------------------------------------------------------------------------------------- | ------------- | | -------------- | ----------------------------------------------------------------------------------------------------------- | ------------- |
| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` | | `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` |
| `--projectId` | Used to link a local project to the platform (required only if injecting via the service token method) | `None` | | `--projectId` | Used to link a local project to the platform (required only if injecting via the service token method) | None |
| `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` | | `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` |
| `--command` | Pass secrets into chained commands (e.g., `"first-command && second-command; more-commands..."`) | None |
+1 -1
View File
@@ -23,7 +23,7 @@ Mandatory variables in the `.env` file:
1. Keys and JWT variables 1. Keys and JWT variables
![image](https://user-images.githubusercontent.com/118568289/206791534-9c9d1431-e83d-49c0-8a54-b373ed0df820.png) ![image](https://user-images.githubusercontent.com/8071263/208800914-f468c2ad-c6a8-4da7-8ffd-eece5d7f08d2.png)
The `.env.example` has these variables empty, you can self generate the `JWT and ENCRYPTION_KEY` with this [32-byte random hex strings generator](https://www.browserling.com/tools/random-hex). The `.env.example` has these variables empty, you can self generate the `JWT and ENCRYPTION_KEY` with this [32-byte random hex strings generator](https://www.browserling.com/tools/random-hex).
Binary file not shown.

After

Width:  |  Height:  |  Size: 842 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

+5
View File
@@ -0,0 +1,5 @@
---
title: "Circle CI"
---
Coming soon.
+5
View File
@@ -0,0 +1,5 @@
---
title: "Fly.io"
---
Coming soon.
+16 -13
View File
@@ -1,26 +1,29 @@
--- ---
title: "Heroku" title: "Heroku"
description: "With this integration, you can automatically sync your secrets to Heroku as soon as you update secrets in Infisical."
--- ---
## Instructions Prerequisites:
### Step 1: Open the integrations console - Set up and add envars to [Infisical Cloud](https://app.infisical.com)
Open the Infisical Dashboard. Choose the project in which you want to set up the intergation. Go to the integrations tab in the left sidebar. ## Navigate to your project's integrations tab
### Step 2: Authenticate with Heroku ![integrations](../../images/integrations.png)
Click on "Heroku" tile. Log in if required and provide the necessary permissions to Infisical. You will afterwards be redirected back to the integrations page. ## Authorize Infisical for Heroku
Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. With any questions, reach out [email protected]. Press on the Heroku tile and grant Infisical access to your Heroku account.
### Step 3: Start integration ![integrations heroku authorization](../../images/integrations-heroku-auth.png)
Choose a Heroku App that you want to sync the secrets to, and the Infisical project environment that you want to sync the secrets from. Start the integration.
The integration should now show status 'In Sync'. Every time you edit secrets, they will be automatically pushed to Heroku.
<Info> <Info>
If you need to update your integration, you will have to delete the current one and create a new one. If this is your project's first cloud integration, then you'll have to grant Infisical access to your project's environment variables.
Although this step breaks E2EE, it's necessary for Infisical to sync the environment variables to the cloud platform.
</Info> </Info>
## Start integration
Select which Infisical environment secrets you want to sync to which Heroku app and press start integration to start syncing secrets to Heroku.
![integrations heroku](../../images/integrations-heroku.png)
+32
View File
@@ -0,0 +1,32 @@
---
title: "Netlify"
---
<Warning>
Infisical integrates with Netlify's new environment variable experience. If your site uses Netlify's old environment variable experience, you'll have to upgrade it to the new one to use this integration.
</Warning>
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
## Navigate to your project's integrations tab
![integrations](../../images/integrations.png)
## Authorize Infisical for Netlify
Press on the Netlify tile and grant Infisical access to your Netlify account.
![integrations netlify authorization](../../images/integrations-netlify-auth.png)
<Info>
If this is your project's first cloud integration, then you'll have to grant Infisical access to your project's environment variables.
Although this step breaks E2EE, it's necessary for Infisical to sync the environment variables to the cloud platform.
</Info>
## Start integration
Select which Infisical environment secrets you want to sync to which Netlify app and context. Lastly, press start integration to start syncing secrets to Netlify.
![integrations netlify](../../images/integrations-netlify.png)
+5
View File
@@ -0,0 +1,5 @@
---
title: "Render"
---
Coming soon.
+19 -1
View File
@@ -2,4 +2,22 @@
title: "Vercel" title: "Vercel"
--- ---
Coming soon. Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
## Navigate to your project's integrations tab
![integrations](../../images/integrations.png)
## Authorize Infisical for Vercel
Press on the Vercel tile and grant Infisical access to your Vercel account.
![integrations vercel authorization](../../images/integrations-vercel-auth.png)
## Start integration
Select which Infisical environment secrets you want to sync to which Vercel app and environment. Lastly, press start integration to start syncing secrets to Vercel.
![integrations vercel](../../images/integrations-vercel.png)
+15 -12
View File
@@ -1,5 +1,5 @@
--- ---
title: "Overview" title: 'Overview'
--- ---
Integrations allow environment variables to be synced from Infisical into your local development workflow, CI/CD pipelines, and production infrastructure. Integrations allow environment variables to be synced from Infisical into your local development workflow, CI/CD pipelines, and production infrastructure.
@@ -10,18 +10,10 @@ Missing an integration? Throw in a [request](https://github.com/Infisical/infisi
| -------------------------------------------------------- | --------- | ----------- | | -------------------------------------------------------- | --------- | ----------- |
| [Docker](/integrations/platforms/docker) | Platform | Available | | [Docker](/integrations/platforms/docker) | Platform | Available |
| [Docker-Compose](/integrations/platforms/docker-compose) | Platform | Available | | [Docker-Compose](/integrations/platforms/docker-compose) | Platform | Available |
| Kubernetes | Platform | Coming soon | | [Kubernetes](/integrations/platforms/kubernetes) | Platform | Available |
| [Heroku](/integrations/cloud/heroku) | Cloud | Available | | [Heroku](/integrations/cloud/heroku) | Cloud | Available |
| [Vercel](/integrations/cloud/vercel) | Cloud | Coming soon | | [Vercel](/integrations/cloud/vercel) | Cloud | Available |
| AWS | Cloud | Coming soon | | [Netlify](/integrations/cloud/netlify) | Cloud | Available |
| GCP | Cloud | Coming soon |
| Azure | Cloud | Coming soon |
| DigitalOcean | Cloud | Coming soon |
| GitLab | CI/CD | Coming soon |
| CircleCI | CI/CD | Coming soon |
| TravisCI | CI/CD | Coming soon |
| GitHub Actions | CI/CD | Coming soon |
| Jenkins | CI/CD | Coming soon |
| [React](/integrations/frameworks/react) | Framework | Available | | [React](/integrations/frameworks/react) | Framework | Available |
| [Vue](/integrations/frameworks/vue) | Framework | Available | | [Vue](/integrations/frameworks/vue) | Framework | Available |
| [Express](/integrations/frameworks/express) | Framework | Available | | [Express](/integrations/frameworks/express) | Framework | Available |
@@ -36,3 +28,14 @@ Missing an integration? Throw in a [request](https://github.com/Infisical/infisi
| [Flask](/integrations/frameworks/flask) | Framework | Available | | [Flask](/integrations/frameworks/flask) | Framework | Available |
| [Laravel](/integrations/frameworks/laravel) | Framework | Available | | [Laravel](/integrations/frameworks/laravel) | Framework | Available |
| [Ruby on Rails](/integrations/frameworks/rails) | Framework | Available | | [Ruby on Rails](/integrations/frameworks/rails) | Framework | Available |
| [Render](/integrations/cloud/render) | Cloud | Coming soon |
| [Fly.io](/integrations/cloud/flyio) | Cloud | Coming soon |
| AWS | Cloud | Coming soon |
| GCP | Cloud | Coming soon |
| Azure | Cloud | Coming soon |
| DigitalOcean | Cloud | Coming soon |
| GitLab | CI/CD | Coming soon |
| [CircleCI](/integrations/cicd/circleci) | CI/CD | Coming soon |
| TravisCI | CI/CD | Coming soon |
| GitHub Actions | CI/CD | Coming soon |
| Jenkins | CI/CD | Coming soon |
+161
View File
@@ -0,0 +1,161 @@
---
title: 'Kubernetes'
---
The Infisical Secrets Operator is a custom Kubernetes controller that helps keep secrets in a cluster up to date by synchronizing them.
It is installed in its own namespace within the cluster and follows strict RBAC policies.
The operator uses InfisicalSecret custom resources to identify which secrets to sync and where to store them.
It is responsible for continuously updating managed secrets, and in the future may also automatically reload deployments that use them as needed.
## Install Operator
The operator can be install via [Helm](helm.sh) or [kubectl](https://github.com/kubernetes/kubectl)
<Tabs>
<Tab title="Helm">
Install Infisical Helm repository
```bash
helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/'
helm repo update
```
Install the Helm chart
```bash
helm install --generate-name infisical-helm-charts/secrets-operator
```
</Tab>
<Tab title="Kubectl">
The operator will be installed in `infisical-operator-system` namespace
```
kubectl apply -f https://raw.githubusercontent.com/Infisical/infisical/main/k8-operator/kubectl-install/install-secrets-operator.yaml
```
</Tab>
</Tabs>
## Sync Infisical Secrets to your cluster
To retrieve secrets from an Infisical project and store them in your Kubernetes cluster, you can use the InfisicalSecret custom resource.
This resource is available after installing the Infisical operator. In order to specify the Infisical Token location and the location where the retrieved secrets should be stored, you can use the `tokenSecretReference` and `managedSecretReference` fields within the InfisicalSecret resource.
<Accordion title="tokenSecretReference">
The `tokenSecretReference` field in the InfisicalSecret resource is used to specify the location of the Infisical Token, which is required for authenticating and retrieving secrets from an Infisical project.
To create a Kubernetes secret containing an [Infisical Token](../../getting-started/dashboard/token), you can run the following command.
``` bash
kubectl create secret generic service-token --from-literal=infisicalToken=<infisical-token-here>
```
Once the secret is created, add the name and namespace of the secret under `tokenSecretReference` field in the InfisicalSecret custom resource.
{' '}
<Info>
No matter what the name of the secret is or its namespace, it must contain a
key named `infisicalToken` with a valid Infisical Token as the value
</Info>
</Accordion>
<Accordion title="managedSecretReference">
The `managedSecretReference` field in the InfisicalSecret resource is used to specify the location where secrets retrieved from an Infisical project should be stored.
You should specify the name and namespace of the Kubernetes secret that will hold these secrets. The operator will create the secret for you, you just need to provide its name and namespace.
It is recommended that the managed secret be created in the same namespace as the deployment that will use it.
</Accordion>
```yaml
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
# Name of of this InfisicalSecret resource
name: infisicalsecret-sample
spec:
# The host that should be used to pull secrets from. The default value is https://infisical.com/api.
hostAPI: https://infisical.com/api
# The Infisical project from which to pull secrets from
projectId: 62faf98ae0b05e8529b5da46
# The environment (dev, prod, testing, etc.) of the above project from where secrets should be pulled from
environment: dev
# The Kubernetes secret the stores the Infisical token
tokenSecretReference:
# Kubernetes secret name
secretName: service-token
# The secret namespace
secretNamespace: default
# The Kubernetes secret that Infisical Operator will create and populate with secrets from the above project
managedSecretReference:
# The name of managed Kubernetes secret that should be created
secretName: managed-secret
# The namespace the managed secret should be installed in
secretNamespace: default
```
## Verify
To use the InfisicalSecret custom resource in your deployment, you can simply reference the managed secret specified in the `managedSecretReference` field as you would any other Kubernetes secret.
To verify that the operator has successfully created the managed secret, you can check the secrets in the namespace that was specified.
```bash
# Verify managed secret is created
kubectl get secrets -n <namespace of managed secret>
```
<Info>
The Infisical secrets will be synced and stored into the managed secret every
5 minutes.
</Info>
## Troubleshoot
If the operator is unable to fetch secrets from the API, it will not affect the managed Kubernetes secret.
It will continue attempting to reconnect to the API indefinitely.
The InfisicalSecret resource uses the `status.conditions` field to report its current state and any errors encountered.
```yaml
$ kubectl get infisicalSecrets
NAME AGE
infisicalsecret-sample 12s
$ kubectl describe infisicalSecret infisicalsecret-sample
...
Spec:
...
Status:
Conditions:
Last Transition Time: 2022-12-18T04:29:09Z
Message: Infisical controller has located the Infisical token in provided Kubernetes secret
Reason: OK
Status: True
Type: secrets.infisical.com/LoadedInfisicalToken
Last Transition Time: 2022-12-18T04:29:10Z
Message: Failed to update secret because: 400 Bad Request
Reason: Error
Status: False
Type: secrets.infisical.com/ReadyToSyncSecrets
Events: <none>
```
## Uninstall Operator
The managed secret created by the operator will not be deleted when the operator is uninstalled.
<Tabs>
<Tab title="Helm">
Install Infisical Helm repository
```bash
helm uninstall add <release name>
```
</Tab>
<Tab title="Kubectl">
```
kubectl delete -f https://raw.githubusercontent.com/Infisical/infisical/main/k8-operator/kubectl-install/install-secrets-operator.yaml
```
</Tab>
</Tabs>
+18 -7
View File
@@ -21,7 +21,9 @@
"to": "#F8B7BD" "to": "#F8B7BD"
} }
}, },
"topbarLinks": [{ "name": "Log In", "url": "https://app.infisical.com/login" }], "topbarLinks": [
{ "name": "Log In", "url": "https://app.infisical.com/login" }
],
"topbarCtaButton": { "topbarCtaButton": {
"name": "Start for Free", "name": "Start for Free",
"url": "https://app.infisical.com/signup" "url": "https://app.infisical.com/signup"
@@ -116,24 +118,30 @@
}, },
{ {
"group": "Integrations", "group": "Integrations",
"pages": [ "pages": ["integrations/overview"]
"integrations/overview"
]
}, },
{ {
"group": "Platforms", "group": "Platforms",
"pages": [ "pages": [
"integrations/platforms/docker", "integrations/platforms/docker",
"integrations/platforms/docker-compose" "integrations/platforms/docker-compose",
"integrations/platforms/kubernetes"
] ]
}, },
{ {
"group": "Cloud", "group": "Cloud",
"pages": [ "pages": [
"integrations/cloud/heroku", "integrations/cloud/heroku",
"integrations/cloud/vercel" "integrations/cloud/vercel",
"integrations/cloud/netlify",
"integrations/cloud/render",
"integrations/cloud/flyio"
] ]
}, },
{
"group": "CI/CD",
"pages": ["integrations/cicd/circleci"]
},
{ {
"group": "Frameworks", "group": "Frameworks",
"pages": [ "pages": [
@@ -171,5 +179,8 @@
] ]
} }
], ],
"backgroundImage": "/images/background.png" "backgroundImage": "/images/background.png",
"integrations": {
"intercom": "hsg644ru"
}
} }
+1 -1
View File
@@ -10,7 +10,7 @@ WORKDIR /app
COPY package.json package-lock.json next.config.js ./ COPY package.json package-lock.json next.config.js ./
# Install dependencies # Install dependencies
RUN npm ci --only-production RUN npm ci --only-production --ignore-scripts
# Rebuild the source code only when needed # Rebuild the source code only when needed
+1 -1
View File
@@ -9,7 +9,7 @@ COPY package.json ./
COPY package-lock.json ./ COPY package-lock.json ./
# Install # Install
RUN npm install RUN npm install --ignore-scripts
# Copy over next.js config # Copy over next.js config
COPY next.config.js ./next.config.js COPY next.config.js ./next.config.js
-20
View File
@@ -1,20 +0,0 @@
# Base layer
FROM node:16-alpine
# Set the working directory
WORKDIR /app
# Copy over dependency files
COPY package.json ./
COPY package-lock.json ./
# Install
RUN npm install
# Copy over next.js config
COPY next.config.js ./next.config.js
# Copy all files
COPY . .
CMD ["npm", "run", "start:docker"]
+4 -4
View File
@@ -10,10 +10,10 @@ import { Listbox, Transition } from "@headlessui/react";
interface ListBoxProps { interface ListBoxProps {
selected: string; selected: string;
onChange: () => void; onChange: (arg: string) => void;
data: string[]; data: string[] | null;
text: string; text?: string;
buttonAction: () => void; buttonAction?: () => void;
isFull?: boolean; isFull?: boolean;
} }
+1 -1
View File
@@ -9,7 +9,7 @@ import {
const classNames = require("classnames"); const classNames = require("classnames");
type ButtonProps = { type ButtonProps = {
text: string; text?: string;
onButtonPressed: () => void; onButtonPressed: () => void;
loading?: boolean; loading?: boolean;
color?: string; color?: string;
@@ -1,30 +1,32 @@
import React from "react"; import React from "react";
import Image from "next/image"; import Image from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import {
faCheck, faCheck,
faX, faX,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import deleteIntegrationAuth from "../../pages/api/integrations/DeleteIntegrationAuth"; import deleteIntegrationAuth from "../../pages/api/integrations/DeleteIntegrationAuth";
interface CloudIntegrationOption { interface CloudIntegrationOption {
isAvailable: Boolean; isAvailable: boolean;
name: string; name: string;
type: string; type: string;
clientId: string; clientId: string;
docsLink: string; docsLink: string;
slug: string;
} }
interface IntegrationAuth { interface IntegrationAuth {
id: string; _id: string;
integration: string; integration: string;
} }
interface Props { interface Props {
cloudIntegrationOption: CloudIntegrationOption; cloudIntegrationOption: CloudIntegrationOption;
setSelectedIntegrationOption: () => void; setSelectedIntegrationOption: (cloudIntegration: CloudIntegrationOption) => void;
integrationOptionPress: () => void; integrationOptionPress: (cloudIntegrationOption: CloudIntegrationOption) => void;
integrationAuths: IntegrationAuth[]; integrationAuths: IntegrationAuth[];
} }
@@ -45,9 +47,7 @@ const CloudIntegration = ({
onClick={() => { onClick={() => {
if (!cloudIntegrationOption.isAvailable) return; if (!cloudIntegrationOption.isAvailable) return;
setSelectedIntegrationOption(cloudIntegrationOption); setSelectedIntegrationOption(cloudIntegrationOption);
integrationOptionPress({ integrationOptionPress(cloudIntegrationOption);
integrationOption: cloudIntegrationOption
});
}} }}
key={cloudIntegrationOption.name} key={cloudIntegrationOption.name}
> >
@@ -1,11 +1,14 @@
import React from "react"; import React from "react";
import CloudIntegration from "./CloudIntegration"; import CloudIntegration from "./CloudIntegration";
interface CloudIntegrationOption { interface CloudIntegrationOption {
isAvailable: boolean;
name: string; name: string;
type: string; type: string;
clientId: string; clientId: string;
docsLink: string; docsLink: string;
slug: string;
} }
interface Props { interface Props {
@@ -1,14 +1,17 @@
import React from "react"; import React from "react";
import FrameworkIntegration from "./FrameworkIntegration"; import FrameworkIntegration from "./FrameworkIntegration";
interface Framework { interface Framework {
name: string; name: string;
image: string; image: string;
link: string; link: string;
slug: string;
docsLink: string;
} }
interface Props { interface Props {
framework: Framework frameworks: [Framework]
} }
const FrameworkIntegrationSection = ({ frameworks }: Props) => { const FrameworkIntegrationSection = ({ frameworks }: Props) => {
@@ -6,23 +6,33 @@ import {
faX, faX,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
envMapping,
reverseEnvMapping,
reverseContextNetlifyMapping
} from "../../public/data/frequentConstants";
import updateIntegration from "../../pages/api/integrations/updateIntegration"
import deleteIntegration from "../../pages/api/integrations/DeleteIntegration"
import getIntegrationApps from "../../pages/api/integrations/GetIntegrationApps";
import Button from "~/components/basic/buttons/Button"; import Button from "~/components/basic/buttons/Button";
import ListBox from "~/components/basic/Listbox"; import ListBox from "~/components/basic/Listbox";
import deleteIntegration from "../../pages/api/integrations/DeleteIntegration"
import getIntegrationApps from "../../pages/api/integrations/GetIntegrationApps";
import updateIntegration from "../../pages/api/integrations/updateIntegration"
import {
contextNetlifyMapping,
envMapping,
reverseContextNetlifyMapping,
reverseEnvMapping,
} from "../../public/data/frequentConstants";
interface Integration { interface Integration {
_id: string;
app?: string; app?: string;
environment: string; environment: string;
integration: string; integration: string;
integrationAuth: string; integrationAuth: string;
isActive: Boolean; isActive: boolean;
context: string;
}
interface IntegrationApp {
name: string;
siteId: string;
} }
const Integration = ({ const Integration = ({
@@ -35,39 +45,44 @@ const Integration = ({
); );
const [fileState, setFileState] = useState([]); const [fileState, setFileState] = useState([]);
const router = useRouter(); const router = useRouter();
const [apps, setApps] = useState([]); // integration app objects const [apps, setApps] = useState<IntegrationApp[]>([]); // integration app objects
const [integrationApp, setIntegrationApp] = useState(null); // integration app name const [integrationApp, setIntegrationApp] = useState(""); // integration app name
const [integrationTarget, setIntegrationTarget] = useState(null); // vercel-specific integration param const [integrationTarget, setIntegrationTarget] = useState(""); // vercel-specific integration param
const [integrationContext, setIntegrationContext] = useState(null); // netlify-specific integration param const [integrationContext, setIntegrationContext] = useState(""); // netlify-specific integration param
useEffect(async () => { useEffect(() => {
interface App {
name: string; const loadIntegration = async () => {
siteId?: string; interface App {
name: string;
siteId?: string;
}
const tempApps: [IntegrationApp] = await getIntegrationApps({
integrationAuthId: integration.integrationAuth,
});
setApps(tempApps);
setIntegrationApp(
integration.app ? integration.app : tempApps[0].name
);
switch (integration.integration) {
case "vercel":
setIntegrationTarget("Development");
break;
case "netlify":
setIntegrationContext(integration?.context ? contextNetlifyMapping[integration.context] : "Local development");
break;
default:
break;
}
} }
const tempApps = await getIntegrationApps({ loadIntegration();
integrationAuthId: integration.integrationAuth,
});
setApps(tempApps);
setIntegrationApp(
integration.app ? integration.app : tempApps[0].name
);
switch (integration.integration) {
case "vercel":
setIntegrationTarget("Development");
break;
case "netlify":
setIntegrationContext("All");
break;
default:
break;
}
}, []); }, []);
const renderIntegrationSpecificParams = (integration) => { const renderIntegrationSpecificParams = (integration: Integration) => {
try { try {
switch (integration.integration) { switch (integration.integration) {
case "vercel": case "vercel":
@@ -77,11 +92,11 @@ const Integration = ({
ENVIRONMENT ENVIRONMENT
</div> </div>
<ListBox <ListBox
data={!integration.isActive && [ data={!integration.isActive ? [
"Production", "Production",
"Preview", "Preview",
"Development" "Development"
]} ] : null}
selected={"Production"} selected={"Production"}
onChange={setIntegrationTarget} onChange={setIntegrationTarget}
/> />
@@ -94,13 +109,12 @@ const Integration = ({
CONTEXT CONTEXT
</div> </div>
<ListBox <ListBox
data={!integration.isActive && [ data={!integration.isActive ? [
"All",
"Production", "Production",
"Deploy previews", "Deploy previews",
"Branch deploys", "Branch deploys",
"Local development" "Local development"
]} ] : null}
selected={integrationContext} selected={integrationContext}
onChange={setIntegrationContext} onChange={setIntegrationContext}
/> />
@@ -128,7 +142,9 @@ const Integration = ({
"Production", "Production",
] : null} ] : null}
selected={integrationEnvironment} selected={integrationEnvironment}
onChange={setIntegrationEnvironment} onChange={(environment) => {
setIntegrationEnvironment(environment);
}}
isFull={true} isFull={true}
/> />
</div> </div>
@@ -152,9 +168,11 @@ const Integration = ({
APP APP
</div> </div>
<ListBox <ListBox
data={!integration.isActive && apps.map((app) => app.name)} data={!integration.isActive ? apps.map((app) => app.name) : null}
selected={integrationApp} selected={integrationApp}
onChange={setIntegrationApp} onChange={(app) => {
setIntegrationApp(app);
}}
/> />
</div> </div>
{renderIntegrationSpecificParams(integration)} {renderIntegrationSpecificParams(integration)}
@@ -172,7 +190,10 @@ const Integration = ({
<Button <Button
text="Start Integration" text="Start Integration"
onButtonPressed={async () => { onButtonPressed={async () => {
const siteId = apps.find((app) => app.name === integrationApp).siteId ? apps.find((app) => app.name === integrationApp).siteId : null;
const siteApp = apps.find((app) => app.name === integrationApp); // obj or undefined
const siteId = siteApp?.siteId ? siteApp.siteId : null;
const result = await updateIntegration({ const result = await updateIntegration({
integrationId: integration._id, integrationId: integration._id,
environment: envMapping[integrationEnvironment], environment: envMapping[integrationEnvironment],
@@ -182,6 +203,7 @@ const Integration = ({
context: integrationContext ? reverseContextNetlifyMapping[integrationContext] : null, context: integrationContext ? reverseContextNetlifyMapping[integrationContext] : null,
siteId siteId
}); });
router.reload(); router.reload();
}} }}
color="mineshaft" color="mineshaft"
@@ -1,15 +1,23 @@
import React from "react"; import React from "react";
import Integration from "./Integration";
import guidGenerator from "~/utilities/randomId"; import guidGenerator from "~/utilities/randomId";
interface Integration { import Integration from "./Integration";
}
interface Props { interface Props {
integrations: any integrations: any
} }
interface IntegrationType {
_id: string;
app?: string;
environment: string;
integration: string;
integrationAuth: string;
isActive: boolean;
context: string;
}
const ProjectIntegrationSection = ({ const ProjectIntegrationSection = ({
integrations integrations
}: Props) => { }: Props) => {
@@ -21,12 +29,12 @@ const ProjectIntegrationSection = ({
Manage your integrations of Infisical with third-party services. Manage your integrations of Infisical with third-party services.
</p> </p>
</div> </div>
{integrations.map((integration => ( {integrations.map((integration: IntegrationType) => (
<Integration <Integration
key={guidGenerator()} key={guidGenerator()}
integration={integration} integration={integration}
/> />
)))} ))}
</div> </div>
) : <div></div> ) : <div></div>
} }
@@ -42,9 +42,9 @@ const attemptLogin = async (
async () => { async () => {
const clientPublicKey = client.getPublicKey(); const clientPublicKey = client.getPublicKey();
const { serverPublicKey, salt } = await login1(email, clientPublicKey);
try { try {
const { serverPublicKey, salt } = await login1(email, clientPublicKey);
client.setSalt(salt); client.setSalt(salt);
client.setServerPublicKey(serverPublicKey); client.setServerPublicKey(serverPublicKey);
const clientProof = client.getProof(); // called M1 const clientProof = client.getProof(); // called M1
@@ -4,15 +4,11 @@ const POSTHOG_HOST =
process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com"; process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com";
const STRIPE_PRODUCT_PRO = process.env.NEXT_PUBLIC_STRIPE_PRODUCT_PRO!; const STRIPE_PRODUCT_PRO = process.env.NEXT_PUBLIC_STRIPE_PRODUCT_PRO!;
const STRIPE_PRODUCT_STARTER = process.env.NEXT_PUBLIC_STRIPE_PRODUCT_STARTER!; const STRIPE_PRODUCT_STARTER = process.env.NEXT_PUBLIC_STRIPE_PRODUCT_STARTER!;
const CLIENT_ID_HEROKU = process.env.NEXT_PUBLIC_CLIENT_ID_HEROKU!;
const CLIENT_ID_NETLIFY = process.env.NEXT_PUBLIC_CLIENT_ID_NETLIFY!;
export { export {
ENV, ENV,
POSTHOG_API_KEY, POSTHOG_API_KEY,
POSTHOG_HOST, POSTHOG_HOST,
STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_PRO,
STRIPE_PRODUCT_STARTER, STRIPE_PRODUCT_STARTER
CLIENT_ID_HEROKU,
CLIENT_ID_NETLIFY
}; };
-22
View File
@@ -60,7 +60,6 @@
"eslint-import-resolver-typescript": "^3.5.2", "eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-simple-import-sort": "^8.0.0", "eslint-plugin-simple-import-sort": "^8.0.0",
"postcss": "^8.4.14", "postcss": "^8.4.14",
"prettier": "2.7.1",
"tailwindcss": "^3.1.4", "tailwindcss": "^3.1.4",
"typescript": "^4.9.3" "typescript": "^4.9.3"
} }
@@ -5999,21 +5998,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/process-nextick-args": { "node_modules/process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -11950,12 +11934,6 @@
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true "dev": true
}, },
"prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true
},
"process-nextick-args": { "process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+1 -1
View File
@@ -1,6 +1,7 @@
{ {
"private": true, "private": true,
"scripts": { "scripts": {
"prepare": "cd .. && npm install",
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
@@ -63,7 +64,6 @@
"eslint-import-resolver-typescript": "^3.5.2", "eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-simple-import-sort": "^8.0.0", "eslint-plugin-simple-import-sort": "^8.0.0",
"postcss": "^8.4.14", "postcss": "^8.4.14",
"prettier": "2.7.1",
"tailwindcss": "^3.1.4", "tailwindcss": "^3.1.4",
"typescript": "^4.9.3" "typescript": "^4.9.3"
} }
+1 -1
View File
@@ -7,7 +7,7 @@ interface BotKey {
interface Props { interface Props {
botId: string; botId: string;
isActive: Boolean; isActive: boolean;
botKey: BotKey; botKey: BotKey;
} }
@@ -22,6 +22,15 @@ const updateIntegration = ({
target, target,
context, context,
siteId siteId
}: {
integrationId: string,
app: string,
environment: string,
isActive: boolean,
target: string | null,
context: string | null,
siteId: string | null
}) => { }) => {
return SecurityClient.fetchCall( return SecurityClient.fetchCall(
"/api/v1/integration/" + integrationId, "/api/v1/integration/" + integrationId,
@@ -40,7 +49,7 @@ const updateIntegration = ({
}), }),
} }
).then(async (res) => { ).then(async (res) => {
if (res.status == 200) { if (res && res.status == 200) {
return res; return res;
} else { } else {
console.log("Failed to start an integration"); console.log("Failed to start an integration");
+20 -19
View File
@@ -2,20 +2,22 @@ import React, { useEffect, useState } from "react";
import Head from "next/head"; import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import NavHeader from "~/components/navigation/NavHeader";
import Integration from "~/components/integrations/Integration";
import FrameworkIntegrationSection from "~/components/integrations/FrameworkIntegrationSection";
import CloudIntegrationSection from "~/components/integrations/CloudIntegrationSection";
import IntegrationSection from "~/components/integrations/IntegrationSection";
import frameworkIntegrationOptions from "../../public/json/frameworkIntegrations.json";
import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations";
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
import getIntegrationOptions from "../api/integrations/GetIntegrationOptions";
import getBot from "../api/bot/getBot";
import setBotActiveStatus from "../api/bot/setBotActiveStatus";
import getLatestFileKey from "../api/workspace/getLatestFileKey";
import ActivateBotDialog from "~/components/basic/dialog/ActivateBotDialog"; import ActivateBotDialog from "~/components/basic/dialog/ActivateBotDialog";
import IntegrationAccessTokenDialog from "~/components/basic/dialog/IntegrationAccessTokenDialog"; import IntegrationAccessTokenDialog from "~/components/basic/dialog/IntegrationAccessTokenDialog";
import CloudIntegrationSection from "~/components/integrations/CloudIntegrationSection";
import FrameworkIntegrationSection from "~/components/integrations/FrameworkIntegrationSection";
import Integration from "~/components/integrations/Integration";
import IntegrationSection from "~/components/integrations/IntegrationSection";
import NavHeader from "~/components/navigation/NavHeader";
import frameworkIntegrationOptions from "../../public/json/frameworkIntegrations.json";
import getBot from "../api/bot/getBot";
import setBotActiveStatus from "../api/bot/setBotActiveStatus";
import getIntegrationOptions from "../api/integrations/GetIntegrationOptions";
import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations";
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
import getLatestFileKey from "../api/workspace/getLatestFileKey";
const { const {
decryptAssymmetric, decryptAssymmetric,
encryptAssymmetric encryptAssymmetric
@@ -132,7 +134,7 @@ export default function Integrations() {
window.location = `https://id.heroku.com/oauth/authorize?client_id=${integrationOption.clientId}&response_type=code&scope=write-protected&state=${state}`; window.location = `https://id.heroku.com/oauth/authorize?client_id=${integrationOption.clientId}&response_type=code&scope=write-protected&state=${state}`;
break; break;
case 'Vercel': case 'Vercel':
window.location = `https://vercel.com/integrations/infisical-dev/new?state=${state}`; window.location = `https://vercel.com/integrations/${integrationOption.clientSlug}/new?state=${state}`;
break; break;
case 'Netlify': case 'Netlify':
window.location = `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=code&redirect_uri=${integrationOption.redirectURL}&state=${state}`; window.location = `https://app.netlify.com/authorize?client_id=${integrationOption.clientId}&response_type=code&redirect_uri=${integrationOption.redirectURL}&state=${state}`;
@@ -158,14 +160,13 @@ export default function Integrations() {
/** /**
* Open dialog to activate bot if bot is not active. * Open dialog to activate bot if bot is not active.
* Otherwise, start integration [integrationOption] * Otherwise, start integration [integrationOption]
* @param {Object} obj * @param {Object} integrationOption - an integration option
* @param {Object} obj.integrationOption - an integration option * @param {String} integrationOption.name
* @param {String} obj.name * @param {String} integrationOption.type
* @param {String} obj.type * @param {String} integrationOption.docsLink
* @param {String} obj.docsLink
* @returns * @returns
*/ */
const integrationOptionPress = ({ integrationOption }) => { const integrationOptionPress = (integrationOption) => {
try { try {
if (bot.isActive) { if (bot.isActive) {
// case: bot is active -> proceed with integration // case: bot is active -> proceed with integration
+10 -12
View File
@@ -16,20 +16,18 @@ export default function Netlify() {
*/ */
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(async () => { useEffect(async () => {
if (state === localStorage.getItem('latestCSRFToken')) {
localStorage.removeItem('latestCSRFToken');
await AuthorizeIntegration({
workspaceId: localStorage.getItem('projectData.id'),
code,
integration: "netlify"
});
router.push("/integrations/" + localStorage.getItem("projectData.id"));
}
try { try {
if (state === localStorage.getItem('latestCSRFToken')) {
localStorage.removeItem('latestCSRFToken');
await AuthorizeIntegration({
workspaceId: localStorage.getItem('projectData.id'),
code,
integration: "netlify"
});
router.push("/integrations/" + localStorage.getItem("projectData.id"));
}
} catch (err) { } catch (err) {
console.error('Netlify integration error: ', err); console.error('Netlify integration error: ', err);
} }
+10 -12
View File
@@ -15,20 +15,18 @@ export default function Vercel() {
*/ */
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(async () => { useEffect(async () => {
if (state === localStorage.getItem('latestCSRFToken')) {
localStorage.removeItem('latestCSRFToken');
await AuthorizeIntegration({
workspaceId: localStorage.getItem('projectData.id'),
code,
integration: "vercel"
});
router.push("/integrations/" + localStorage.getItem("projectData.id"));
}
try { try {
if (state === localStorage.getItem('latestCSRFToken')) {
localStorage.removeItem('latestCSRFToken');
await AuthorizeIntegration({
workspaceId: localStorage.getItem('projectData.id'),
code,
integration: "vercel"
});
router.push("/integrations/" + localStorage.getItem("projectData.id"));
}
} catch (err) { } catch (err) {
console.error('Vercel integration error: ', err); console.error('Vercel integration error: ', err);
} }
+15 -9
View File
@@ -1,23 +1,29 @@
const envMapping = { interface Mapping {
[key: string]: string;
}
const envMapping: Mapping = {
Development: "dev", Development: "dev",
Staging: "staging", Staging: "staging",
Production: "prod", Production: "prod",
Testing: "test", Testing: "test",
}; };
const reverseEnvMapping = { const reverseEnvMapping: Mapping = {
dev: "Development", dev: "Development",
staging: "Staging", staging: "Staging",
prod: "Production", prod: "Production",
test: "Testing", test: "Testing",
}; };
const vercelMapping = { const contextNetlifyMapping: Mapping = {
"dev": "Local development",
"branch-deploy": "Branch deploys",
"deploy-review": "Deploy Previews",
"production": "Production"
} }
const reverseContextNetlifyMapping = { const reverseContextNetlifyMapping: Mapping = {
"All": "all",
"Local development": "dev", "Local development": "dev",
"Branch deploys": "branch-deploy", "Branch deploys": "branch-deploy",
"Deploy Previews": "deploy-preview", "Deploy Previews": "deploy-preview",
@@ -25,7 +31,7 @@ const reverseContextNetlifyMapping = {
} }
export { export {
contextNetlifyMapping,
envMapping, envMapping,
reverseEnvMapping, reverseContextNetlifyMapping,
reverseContextNetlifyMapping reverseEnvMapping}
};
+1
View File
@@ -14,3 +14,4 @@ helm install infisical-helm-charts/<name-of-helm-chart>
#### Available chart names #### Available chart names
- infisical - infisical
- secrets-operator
+1 -1
View File
@@ -7,7 +7,7 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes # This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.3 version: 0.1.4
# This is the version number of the application being deployed. This version number should be # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to # incremented each time you make changes to the application. Versions are not expected to
@@ -20,6 +20,9 @@ spec:
imagePullPolicy: {{ .Values.backend.image.pullPolicy }} imagePullPolicy: {{ .Values.backend.image.pullPolicy }}
ports: ports:
- containerPort: 4000 - containerPort: 4000
envFrom:
- secretRef:
name: {{ .Values.backend.kubeSecretRef }}
env: env:
{{- range $key, $value := .Values.backendEnvironmentVariables }} {{- range $key, $value := .Values.backendEnvironmentVariables }}
{{- if $value | quote | eq "MUST_REPLACE" }} {{- if $value | quote | eq "MUST_REPLACE" }}
@@ -18,6 +18,9 @@ spec:
- name: frontend - name: frontend
image: infisical/frontend image: infisical/frontend
imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} imagePullPolicy: {{ .Values.frontend.image.pullPolicy }}
envFrom:
- secretRef:
name: {{ .Values.frontend.kubeSecretRef }}
env: env:
{{- range $key, $value := .Values.frontendEnvironmentVariables }} {{- range $key, $value := .Values.frontendEnvironmentVariables }}
{{- if $value | quote | eq "MUST_REPLACE" }} {{- if $value | quote | eq "MUST_REPLACE" }}
+23
View File
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
+21
View File
@@ -0,0 +1,21 @@
apiVersion: v2
name: secrets-operator
description: A Helm chart for Infisical secrets
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.1.0"
@@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "secrets-operator.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "secrets-operator.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "secrets-operator.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "secrets-operator.labels" -}}
helm.sh/chart: {{ include "secrets-operator.chart" . }}
{{ include "secrets-operator.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "secrets-operator.selectorLabels" -}}
app.kubernetes.io/name: {{ include "secrets-operator.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "secrets-operator.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "secrets-operator.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
@@ -0,0 +1,108 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "secrets-operator.fullname" . }}-controller-manager
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
{{- include "secrets-operator.labels" . | nindent 4 }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "secrets-operator.fullname" . }}-controller-manager
labels:
app.kubernetes.io/component: manager
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
control-plane: controller-manager
{{- include "secrets-operator.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.controllerManager.replicas }}
selector:
matchLabels:
control-plane: controller-manager
{{- include "secrets-operator.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
control-plane: controller-manager
{{- include "secrets-operator.selectorLabels" . | nindent 8 }}
annotations:
kubectl.kubernetes.io/default-container: manager
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- arm64
- ppc64le
- s390x
- key: kubernetes.io/os
operator: In
values:
- linux
containers:
- args:
- --secure-listen-address=0.0.0.0:8443
- --upstream=http://127.0.0.1:8080/
- --logtostderr=true
- --v=0
env:
- name: KUBERNETES_CLUSTER_DOMAIN
value: {{ .Values.kubernetesClusterDomain }}
image: {{ .Values.controllerManager.kubeRbacProxy.image.repository }}:{{ .Values.controllerManager.kubeRbacProxy.image.tag
| default .Chart.AppVersion }}
name: kube-rbac-proxy
ports:
- containerPort: 8443
name: https
protocol: TCP
resources: {{- toYaml .Values.controllerManager.kubeRbacProxy.resources | nindent
10 }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
- args:
- --health-probe-bind-address=:8081
- --metrics-bind-address=127.0.0.1:8080
- --leader-elect
command:
- /manager
env:
- name: KUBERNETES_CLUSTER_DOMAIN
value: {{ .Values.kubernetesClusterDomain }}
image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag
| default .Chart.AppVersion }}
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
name: manager
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10
}}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
securityContext:
runAsNonRoot: true
serviceAccountName: {{ include "secrets-operator.fullname" . }}-controller-manager
terminationGracePeriodSeconds: 10
@@ -0,0 +1,160 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: infisicalsecrets.secrets.infisical.com
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
labels:
{{- include "secrets-operator.labels" . | nindent 4 }}
spec:
group: secrets.infisical.com
names:
kind: InfisicalSecret
listKind: InfisicalSecretList
plural: infisicalsecrets
singular: infisicalsecret
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: InfisicalSecret is the Schema for the infisicalsecrets API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: InfisicalSecretSpec defines the desired state of InfisicalSecret
properties:
environment:
description: The Infisical environment such as dev, prod, testing
type: string
hostAPI:
default: https://app.infisical.com/api
description: Infisical host to pull secrets from
type: string
managedSecretReference:
properties:
secretName:
description: The name of the Kubernetes Secret
type: string
secretNamespace:
description: The name space where the Kubernetes Secret is located
type: string
required:
- secretName
- secretNamespace
type: object
projectId:
description: The Infisical project id
type: string
tokenSecretReference:
properties:
secretName:
description: The name of the Kubernetes Secret
type: string
secretNamespace:
description: The name space where the Kubernetes Secret is located
type: string
required:
- secretName
- secretNamespace
type: object
required:
- environment
- projectId
type: object
status:
description: InfisicalSecretStatus defines the observed state of InfisicalSecret
properties:
conditions:
items:
description: "Condition contains details for one aspect of the current
state of this API Resource. --- This struct is intended for direct
use as an array at the field path .status.conditions. For example,
\n type FooStatus struct{ // Represents the observations of a foo's
current state. // Known .status.conditions.type are: \"Available\",
\"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge
// +listType=map // +listMapKey=type Conditions []metav1.Condition
`json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\"
protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition
transitioned from one status to another. This should be when
the underlying condition changed. If that is not known, then
using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating details
about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation
that the condition was set based upon. For instance, if .metadata.generation
is currently 12, but the .status.conditions[x].observedGeneration
is 9, the condition is out of date with respect to the current
state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier indicating
the reason for the condition's last transition. Producers of
specific condition types may define expected values and meanings
for this field, and whether the values are considered a guaranteed
API. The value should be a CamelCase string. This field may
not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase.
--- Many .condition.type values are consistent across resources
like Available, but because arbitrary conditions can be useful
(see .node.status.conditions), the ability to deconflict is
important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
type: array
required:
- conditions
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
@@ -0,0 +1,59 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "secrets-operator.fullname" . }}-leader-election-role
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
{{- include "secrets-operator.labels" . | nindent 4 }}
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "secrets-operator.fullname" . }}-leader-election-rolebinding
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
{{- include "secrets-operator.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: '{{ include "secrets-operator.fullname" . }}-leader-election-role'
subjects:
- kind: ServiceAccount
name: '{{ include "secrets-operator.fullname" . }}-controller-manager'
namespace: '{{ .Release.Namespace }}'
@@ -0,0 +1,71 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "secrets-operator.fullname" . }}-manager-role
labels:
{{- include "secrets-operator.labels" . | nindent 4 }}
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- delete
- get
- list
- update
- watch
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- update
- watch
- apiGroups:
- secrets.infisical.com
resources:
- infisicalsecrets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- secrets.infisical.com
resources:
- infisicalsecrets/finalizers
verbs:
- update
- apiGroups:
- secrets.infisical.com
resources:
- infisicalsecrets/status
verbs:
- get
- patch
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "secrets-operator.fullname" . }}-manager-rolebinding
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
{{- include "secrets-operator.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: '{{ include "secrets-operator.fullname" . }}-manager-role'
subjects:
- kind: ServiceAccount
name: '{{ include "secrets-operator.fullname" . }}-controller-manager'
namespace: '{{ .Release.Namespace }}'
@@ -0,0 +1,14 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "secrets-operator.fullname" . }}-metrics-reader
labels:
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
{{- include "secrets-operator.labels" . | nindent 4 }}
rules:
- nonResourceURLs:
- /metrics
verbs:
- get
@@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "secrets-operator.fullname" . }}-controller-manager-metrics-service
labels:
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
control-plane: controller-manager
{{- include "secrets-operator.labels" . | nindent 4 }}
spec:
type: {{ .Values.metricsService.type }}
selector:
control-plane: controller-manager
{{- include "secrets-operator.selectorLabels" . | nindent 4 }}
ports:
{{- .Values.metricsService.ports | toYaml | nindent 2 -}}
@@ -0,0 +1,40 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "secrets-operator.fullname" . }}-proxy-role
labels:
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
{{- include "secrets-operator.labels" . | nindent 4 }}
rules:
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "secrets-operator.fullname" . }}-proxy-rolebinding
labels:
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/part-of: k8-operator
{{- include "secrets-operator.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: '{{ include "secrets-operator.fullname" . }}-proxy-role'
subjects:
- kind: ServiceAccount
name: '{{ include "secrets-operator.fullname" . }}-controller-manager'
namespace: '{{ .Release.Namespace }}'
+32
View File
@@ -0,0 +1,32 @@
controllerManager:
kubeRbacProxy:
image:
repository: gcr.io/kubebuilder/kube-rbac-proxy
tag: v0.13.1
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 5m
memory: 64Mi
manager:
image:
repository: infisical/kubernetes-operator
tag: latest
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 10m
memory: 64Mi
replicas: 1
kubernetesClusterDomain: cluster.local
metricsService:
ports:
- name: https
port: 8443
protocol: TCP
targetPort: https
type: ClusterIP
+12 -1
View File
@@ -1,6 +1,6 @@
# Image URL to use all building/pushing image targets # Image URL to use all building/pushing image targets
IMG ?= controller:latest IMG ?= infisical/kubernetes-operator:latest
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.25.0 ENVTEST_K8S_VERSION = 1.25.0
@@ -36,6 +36,17 @@ all: build
help: ## Display this help. help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
## Chart
helm-chart:
$(KUSTOMIZE) build config/default | helmify ../helm-charts/secrets-operator
## Yaml for Kubectl
kubectl-install: manifests kustomize
mkdir -p kubectl-install
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default > kubectl-install/install-secrets-operator.yaml
##@ Development ##@ Development
.PHONY: manifests .PHONY: manifests
+3 -19
View File
@@ -1,8 +1,8 @@
# k8-operator # k8-operator
// TODO(user): Add simple overview of use/purpose // TODO
## Description ## Description
// TODO(user): An in-depth paragraph about your project and overview of use // TODO
## Getting Started ## Getting Started
You’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster. You’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster.
@@ -42,7 +42,7 @@ make undeploy
``` ```
## Contributing ## Contributing
// TODO(user): Add detailed information on how you would like others to contribute to this project // TODO
### How it works ### How it works
This project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) This project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/)
@@ -76,19 +76,3 @@ make manifests
More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html)
## License
Copyright 2022.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -16,8 +16,8 @@ type KubeSecretReference struct {
// InfisicalSecretSpec defines the desired state of InfisicalSecret // InfisicalSecretSpec defines the desired state of InfisicalSecret
type InfisicalSecretSpec struct { type InfisicalSecretSpec struct {
InfisicalToken KubeSecretReference `json:"infisicalToken,omitempty"` TokenSecretReference KubeSecretReference `json:"tokenSecretReference,omitempty"`
ManagedSecret KubeSecretReference `json:"managedSecret,omitempty"` ManagedSecretReference KubeSecretReference `json:"managedSecretReference,omitempty"`
// The Infisical project id // The Infisical project id
// +kubebuilder:validation:Required // +kubebuilder:validation:Required
@@ -26,6 +26,10 @@ type InfisicalSecretSpec struct {
// The Infisical environment such as dev, prod, testing // The Infisical environment such as dev, prod, testing
// +kubebuilder:validation:Required // +kubebuilder:validation:Required
Environment string `json:"environment"` Environment string `json:"environment"`
// Infisical host to pull secrets from
// +kubebuilder:default="https://app.infisical.com/api"
HostAPI string `json:"hostAPI,omitempty"`
} }
// InfisicalSecretStatus defines the observed state of InfisicalSecret // InfisicalSecretStatus defines the observed state of InfisicalSecret
@@ -88,8 +88,8 @@ func (in *InfisicalSecretList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InfisicalSecretSpec) DeepCopyInto(out *InfisicalSecretSpec) { func (in *InfisicalSecretSpec) DeepCopyInto(out *InfisicalSecretSpec) {
*out = *in *out = *in
out.InfisicalToken = in.InfisicalToken out.TokenSecretReference = in.TokenSecretReference
out.ManagedSecret = in.ManagedSecret out.ManagedSecretReference = in.ManagedSecretReference
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfisicalSecretSpec. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfisicalSecretSpec.
@@ -38,19 +38,11 @@ spec:
environment: environment:
description: The Infisical environment such as dev, prod, testing description: The Infisical environment such as dev, prod, testing
type: string type: string
infisicalToken: hostAPI:
properties: default: https://app.infisical.com/api
secretName: description: Infisical host to pull secrets from
description: The name of the Kubernetes Secret type: string
type: string managedSecretReference:
secretNamespace:
description: The name space where the Kubernetes Secret is located
type: string
required:
- secretName
- secretNamespace
type: object
managedSecret:
properties: properties:
secretName: secretName:
description: The name of the Kubernetes Secret description: The name of the Kubernetes Secret
@@ -65,6 +57,18 @@ spec:
projectId: projectId:
description: The Infisical project id description: The Infisical project id
type: string type: string
tokenSecretReference:
properties:
secretName:
description: The name of the Kubernetes Secret
type: string
secretNamespace:
description: The name space where the Kubernetes Secret is located
type: string
required:
- secretName
- secretNamespace
type: object
required: required:
- environment - environment
- projectId - projectId
@@ -1,12 +1,12 @@
# Adds namespace to all resources. # Adds namespace to all resources.
namespace: k8-operator-system namespace: infisical-operator-system
# Value of this field is prepended to the # Value of this field is prepended to the
# names of all resources, e.g. a deployment named # names of all resources, e.g. a deployment named
# "wordpress" becomes "alices-wordpress". # "wordpress" becomes "alices-wordpress".
# Note that it should also match with the prefix (text before '-') of the namespace # Note that it should also match with the prefix (text before '-') of the namespace
# field above. # field above.
namePrefix: k8-operator- namePrefix: infisical-operator-
# Labels to add to all resources and selectors. # Labels to add to all resources and selectors.
#commonLabels: #commonLabels:
@@ -1,2 +1,8 @@
resources: resources:
- manager.yaml - manager.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: controller
newName: infisical/kubernetes-operator
newTag: latest
+13
View File
@@ -0,0 +1,13 @@
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
name: infisicalsecret-sample
spec:
projectId: 62faf98ae0b05e8529b5da46
environment: dev
tokenSecretReference:
secretName: service-token
secretNamespace: first-project
managedSecretReference:
secretName: managed-secret
secretNamespace: first-project
@@ -1,19 +0,0 @@
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
labels:
app.kubernetes.io/name: infisicalsecret
app.kubernetes.io/instance: infisicalsecret-sample
app.kubernetes.io/part-of: k8-operator
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/created-by: k8-operator
name: infisicalsecret-sample
spec:
projectId: 62faf98ae0b05e8529b5da46
environment: dev
infisicalToken:
secretName: service-token
secretNamespace: default
managedSecret:
secretName: managed-secret
secretNamespace: default
@@ -36,6 +36,8 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
var infisicalSecretCR v1alpha1.InfisicalSecret var infisicalSecretCR v1alpha1.InfisicalSecret
err := r.Get(ctx, req.NamespacedName, &infisicalSecretCR) err := r.Get(ctx, req.NamespacedName, &infisicalSecretCR)
requeueTime := time.Minute * 5
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
log.Info("Infisical Secret not found") log.Info("Infisical Secret not found")
@@ -43,7 +45,7 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
} else { } else {
log.Error(err, "Unable to fetch Infisical Secret from cluster. Will retry") log.Error(err, "Unable to fetch Infisical Secret from cluster. Will retry")
return ctrl.Result{ return ctrl.Result{
RequeueAfter: time.Minute, RequeueAfter: requeueTime,
}, nil }, nil
} }
} }
@@ -58,13 +60,13 @@ func (r *InfisicalSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ
if err != nil { if err != nil {
log.Error(err, "Unable to reconcile Infisical Secret and will try again") log.Error(err, "Unable to reconcile Infisical Secret and will try again")
return ctrl.Result{ return ctrl.Result{
RequeueAfter: time.Minute, RequeueAfter: requeueTime,
}, nil }, nil
} }
// Sync again after the specified time // Sync again after the specified time
return ctrl.Result{ return ctrl.Result{
RequeueAfter: time.Minute, RequeueAfter: requeueTime,
}, nil }, nil
} }
@@ -29,12 +29,12 @@ func (r *InfisicalSecretReconciler) GetKubeSecretByNamespacedName(ctx context.Co
func (r *InfisicalSecretReconciler) GetInfisicalToken(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) (string, error) { func (r *InfisicalSecretReconciler) GetInfisicalToken(ctx context.Context, infisicalSecret v1alpha1.InfisicalSecret) (string, error) {
tokenSecret, err := r.GetKubeSecretByNamespacedName(ctx, types.NamespacedName{ tokenSecret, err := r.GetKubeSecretByNamespacedName(ctx, types.NamespacedName{
Namespace: infisicalSecret.Spec.InfisicalToken.SecretNamespace, Namespace: infisicalSecret.Spec.TokenSecretReference.SecretNamespace,
Name: infisicalSecret.Spec.InfisicalToken.SecretName, Name: infisicalSecret.Spec.TokenSecretReference.SecretName,
}) })
if err != nil { if err != nil {
return "", fmt.Errorf("failed to read Infisical token secret from secret named [%s] in namespace [%s]: with error [%w]", infisicalSecret.Spec.ManagedSecret.SecretName, infisicalSecret.Spec.ManagedSecret.SecretNamespace, err) return "", fmt.Errorf("failed to read Infisical token secret from secret named [%s] in namespace [%s]: with error [%w]", infisicalSecret.Spec.ManagedSecretReference.SecretName, infisicalSecret.Spec.ManagedSecretReference.SecretNamespace, err)
} }
infisicalServiceToken := tokenSecret.Data[INFISICAL_TOKEN_SECRET_KEY_NAME] infisicalServiceToken := tokenSecret.Data[INFISICAL_TOKEN_SECRET_KEY_NAME]
@@ -54,8 +54,8 @@ func (r *InfisicalSecretReconciler) CreateInfisicalManagedKubeSecret(ctx context
// create a new secret as specified by the managed secret spec of CRD // create a new secret as specified by the managed secret spec of CRD
newKubeSecretInstance := &corev1.Secret{ newKubeSecretInstance := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: infisicalSecret.Spec.ManagedSecret.SecretName, Name: infisicalSecret.Spec.ManagedSecretReference.SecretName,
Namespace: infisicalSecret.Spec.ManagedSecret.SecretNamespace, Namespace: infisicalSecret.Spec.ManagedSecretReference.SecretNamespace,
}, },
Type: "Opaque", Type: "Opaque",
Data: plainProcessedSecrets, Data: plainProcessedSecrets,
@@ -94,15 +94,15 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
} }
managedKubeSecret, err := r.GetKubeSecretByNamespacedName(ctx, types.NamespacedName{ managedKubeSecret, err := r.GetKubeSecretByNamespacedName(ctx, types.NamespacedName{
Name: infisicalSecret.Spec.ManagedSecret.SecretName, Name: infisicalSecret.Spec.ManagedSecretReference.SecretName,
Namespace: infisicalSecret.Spec.ManagedSecret.SecretNamespace, Namespace: infisicalSecret.Spec.ManagedSecretReference.SecretNamespace,
}) })
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return fmt.Errorf("something went wrong when fetching the managed Kubernetes secret [%w]", err) return fmt.Errorf("something went wrong when fetching the managed Kubernetes secret [%w]", err)
} }
secretsFromApi, err := api.GetAllEnvironmentVariables(infisicalSecret.Spec.ProjectId, infisicalSecret.Spec.Environment, infisicalToken) secretsFromApi, err := api.GetAllEnvironmentVariables(infisicalSecret.Spec.ProjectId, infisicalSecret.Spec.Environment, infisicalToken, infisicalSecret.Spec.HostAPI)
if err != nil { if err != nil {
return err return err
@@ -0,0 +1,475 @@
apiVersion: v1
kind: Namespace
metadata:
labels:
app.kubernetes.io/component: manager
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: system
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: namespace
app.kubernetes.io/part-of: k8-operator
control-plane: controller-manager
name: infisical-operator-system
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.10.0
creationTimestamp: null
name: infisicalsecrets.secrets.infisical.com
spec:
group: secrets.infisical.com
names:
kind: InfisicalSecret
listKind: InfisicalSecretList
plural: infisicalsecrets
singular: infisicalsecret
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: InfisicalSecret is the Schema for the infisicalsecrets API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: InfisicalSecretSpec defines the desired state of InfisicalSecret
properties:
environment:
description: The Infisical environment such as dev, prod, testing
type: string
hostAPI:
default: https://app.infisical.com/api
description: Infisical host to pull secrets from
type: string
managedSecretReference:
properties:
secretName:
description: The name of the Kubernetes Secret
type: string
secretNamespace:
description: The name space where the Kubernetes Secret is located
type: string
required:
- secretName
- secretNamespace
type: object
projectId:
description: The Infisical project id
type: string
tokenSecretReference:
properties:
secretName:
description: The name of the Kubernetes Secret
type: string
secretNamespace:
description: The name space where the Kubernetes Secret is located
type: string
required:
- secretName
- secretNamespace
type: object
required:
- environment
- projectId
type: object
status:
description: InfisicalSecretStatus defines the observed state of InfisicalSecret
properties:
conditions:
items:
description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: message is a human readable message indicating details about the transition. This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
type: array
required:
- conditions
type: object
type: object
served: true
storage: true
subresources:
status: {}
---
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: controller-manager
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: serviceaccount
app.kubernetes.io/part-of: k8-operator
name: infisical-operator-controller-manager
namespace: infisical-operator-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: leader-election-role
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: role
app.kubernetes.io/part-of: k8-operator
name: infisical-operator-leader-election-role
namespace: infisical-operator-system
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: infisical-operator-manager-role
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- delete
- get
- list
- update
- watch
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- update
- watch
- apiGroups:
- secrets.infisical.com
resources:
- infisicalsecrets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- secrets.infisical.com
resources:
- infisicalsecrets/finalizers
verbs:
- update
- apiGroups:
- secrets.infisical.com
resources:
- infisicalsecrets/status
verbs:
- get
- patch
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: metrics-reader
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: clusterrole
app.kubernetes.io/part-of: k8-operator
name: infisical-operator-metrics-reader
rules:
- nonResourceURLs:
- /metrics
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: proxy-role
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: clusterrole
app.kubernetes.io/part-of: k8-operator
name: infisical-operator-proxy-role
rules:
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: leader-election-rolebinding
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: rolebinding
app.kubernetes.io/part-of: k8-operator
name: infisical-operator-leader-election-rolebinding
namespace: infisical-operator-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: infisical-operator-leader-election-role
subjects:
- kind: ServiceAccount
name: infisical-operator-controller-manager
namespace: infisical-operator-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: manager-rolebinding
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: clusterrolebinding
app.kubernetes.io/part-of: k8-operator
name: infisical-operator-manager-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: infisical-operator-manager-role
subjects:
- kind: ServiceAccount
name: infisical-operator-controller-manager
namespace: infisical-operator-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: proxy-rolebinding
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: clusterrolebinding
app.kubernetes.io/part-of: k8-operator
name: infisical-operator-proxy-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: infisical-operator-proxy-role
subjects:
- kind: ServiceAccount
name: infisical-operator-controller-manager
namespace: infisical-operator-system
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: controller-manager-metrics-service
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: service
app.kubernetes.io/part-of: k8-operator
control-plane: controller-manager
name: infisical-operator-controller-manager-metrics-service
namespace: infisical-operator-system
spec:
ports:
- name: https
port: 8443
protocol: TCP
targetPort: https
selector:
control-plane: controller-manager
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: manager
app.kubernetes.io/created-by: k8-operator
app.kubernetes.io/instance: controller-manager
app.kubernetes.io/managed-by: kustomize
app.kubernetes.io/name: deployment
app.kubernetes.io/part-of: k8-operator
control-plane: controller-manager
name: infisical-operator-controller-manager
namespace: infisical-operator-system
spec:
replicas: 1
selector:
matchLabels:
control-plane: controller-manager
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: manager
labels:
control-plane: controller-manager
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- arm64
- ppc64le
- s390x
- key: kubernetes.io/os
operator: In
values:
- linux
containers:
- args:
- --secure-listen-address=0.0.0.0:8443
- --upstream=http://127.0.0.1:8080/
- --logtostderr=true
- --v=0
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.13.1
name: kube-rbac-proxy
ports:
- containerPort: 8443
name: https
protocol: TCP
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 5m
memory: 64Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
- args:
- --health-probe-bind-address=:8081
- --metrics-bind-address=127.0.0.1:8080
- --leader-elect
command:
- /manager
image: infisical/kubernetes-operator:latest
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
name: manager
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 10m
memory: 64Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
securityContext:
runAsNonRoot: true
serviceAccountName: infisical-operator-controller-manager
terminationGracePeriodSeconds: 10
+4 -6
View File
@@ -13,10 +13,8 @@ import (
"golang.org/x/crypto/nacl/box" "golang.org/x/crypto/nacl/box"
) )
const INFISICAL_URL = "https://app.infisical.com/api" func GetAllEnvironmentVariables(projectId string, envName string, infisicalToken string, hostAPI string) ([]models.SingleEnvironmentVariable, error) {
envsFromApi, err := GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId, hostAPI)
func GetAllEnvironmentVariables(projectId string, envName string, infisicalToken string) ([]models.SingleEnvironmentVariable, error) {
envsFromApi, err := GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -24,7 +22,7 @@ func GetAllEnvironmentVariables(projectId string, envName string, infisicalToken
return SubstituteSecrets(envsFromApi), nil return SubstituteSecrets(envsFromApi), nil
} }
func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string, projectId string) ([]models.SingleEnvironmentVariable, error) { func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string, projectId string, hostAPI string) ([]models.SingleEnvironmentVariable, error) {
if infisicalToken == "" || projectId == "" || envName == "" { if infisicalToken == "" || projectId == "" || envName == "" {
return nil, errors.New("infisical token, project id and or environment name cannot be empty") return nil, errors.New("infisical token, project id and or environment name cannot be empty")
} }
@@ -44,7 +42,7 @@ func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string,
SetQueryParam("environment", envName). SetQueryParam("environment", envName).
SetQueryParam("channel", "cli"). SetQueryParam("channel", "cli").
SetResult(&pullSecretsByInfisicalTokenResponse). SetResult(&pullSecretsByInfisicalTokenResponse).
Get(fmt.Sprintf("%v/v1/secret/%v/service-token", INFISICAL_URL, projectId)) Get(fmt.Sprintf("%v/v1/secret/%v/service-token", hostAPI, projectId))
if err != nil { if err != nil {
return nil, err return nil, err
+1 -23
View File
@@ -8,8 +8,7 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"eslint": "^8.29.0", "eslint": "^8.29.0",
"husky": "^8.0.2", "husky": "^8.0.2"
"prettier": "^2.8.1"
} }
}, },
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
@@ -899,21 +898,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/prettier": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz",
"integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -1809,12 +1793,6 @@
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true "dev": true
}, },
"prettier": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz",
"integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==",
"dev": true
},
"punycode": { "punycode": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+2 -5
View File
@@ -14,15 +14,12 @@
"prepare": "husky install" "prepare": "husky install"
}, },
"lint-staged": { "lint-staged": {
"**/*": "prettier --write --ignore-unknown",
"*.{js,jsx,ts,tsx}": [ "*.{js,jsx,ts,tsx}": [
"eslint --fix", "eslint --fix"
"prettier --write"
] ]
}, },
"devDependencies": { "devDependencies": {
"eslint": "^8.29.0", "eslint": "^8.29.0",
"husky": "^8.0.2", "husky": "^8.0.2"
"prettier": "^2.8.1"
} }
} }