Compare commits

..

7 Commits

Author SHA1 Message Date
=
6826b1c242 feat: made review changed 2025-08-04 23:36:05 +05:30
Daniel Hougaard
35012fde03 fix: added ldap identity auth example 2025-08-04 21:57:07 +04:00
=
4b9e57ae61 feat: review changes for reptile 2025-08-01 21:10:26 +05:30
Akhil Mohan
eb27983990 Update k8-operator/packages/util/kubernetes.go
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-08-01 21:08:33 +05:30
=
fa311b032c feat: removed comments 2025-08-01 21:06:17 +05:30
=
71651f85fe docs: ldap auth in operator 2025-08-01 21:04:44 +05:30
=
d28d3449de feat: added ldap authentication to operator 2025-08-01 21:04:29 +05:30
82 changed files with 1301 additions and 1218 deletions

View File

@@ -38,7 +38,6 @@
"@octokit/core": "^5.2.1", "@octokit/core": "^5.2.1",
"@octokit/plugin-paginate-graphql": "^4.0.1", "@octokit/plugin-paginate-graphql": "^4.0.1",
"@octokit/plugin-retry": "^5.0.5", "@octokit/plugin-retry": "^5.0.5",
"@octokit/request": "8.4.1",
"@octokit/rest": "^20.0.2", "@octokit/rest": "^20.0.2",
"@octokit/webhooks-types": "^7.3.1", "@octokit/webhooks-types": "^7.3.1",
"@octopusdeploy/api-client": "^3.4.1", "@octopusdeploy/api-client": "^3.4.1",
@@ -9778,6 +9777,18 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/@octokit/auth-app/node_modules/@octokit/endpoint": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz",
"integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==",
"dependencies": {
"@octokit/types": "^13.0.0",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/auth-app/node_modules/@octokit/openapi-types": { "node_modules/@octokit/auth-app/node_modules/@octokit/openapi-types": {
"version": "22.2.0", "version": "22.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
@@ -9824,6 +9835,11 @@
"node": "14 || >=16.14" "node": "14 || >=16.14"
} }
}, },
"node_modules/@octokit/auth-app/node_modules/universal-user-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q=="
},
"node_modules/@octokit/auth-oauth-app": { "node_modules/@octokit/auth-oauth-app": {
"version": "8.1.1", "version": "8.1.1",
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz",
@@ -9839,6 +9855,18 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/@octokit/auth-oauth-app/node_modules/@octokit/endpoint": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz",
"integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==",
"dependencies": {
"@octokit/types": "^13.0.0",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/auth-oauth-app/node_modules/@octokit/openapi-types": { "node_modules/@octokit/auth-oauth-app/node_modules/@octokit/openapi-types": {
"version": "22.2.0", "version": "22.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
@@ -9877,6 +9905,11 @@
"@octokit/openapi-types": "^22.2.0" "@octokit/openapi-types": "^22.2.0"
} }
}, },
"node_modules/@octokit/auth-oauth-app/node_modules/universal-user-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q=="
},
"node_modules/@octokit/auth-oauth-device": { "node_modules/@octokit/auth-oauth-device": {
"version": "7.1.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz",
@@ -9891,6 +9924,18 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/@octokit/auth-oauth-device/node_modules/@octokit/endpoint": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz",
"integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==",
"dependencies": {
"@octokit/types": "^13.0.0",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/auth-oauth-device/node_modules/@octokit/openapi-types": { "node_modules/@octokit/auth-oauth-device/node_modules/@octokit/openapi-types": {
"version": "22.2.0", "version": "22.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
@@ -9929,6 +9974,11 @@
"@octokit/openapi-types": "^22.2.0" "@octokit/openapi-types": "^22.2.0"
} }
}, },
"node_modules/@octokit/auth-oauth-device/node_modules/universal-user-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q=="
},
"node_modules/@octokit/auth-oauth-user": { "node_modules/@octokit/auth-oauth-user": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz",
@@ -9944,6 +9994,18 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/@octokit/auth-oauth-user/node_modules/@octokit/endpoint": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz",
"integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==",
"dependencies": {
"@octokit/types": "^13.0.0",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/auth-oauth-user/node_modules/@octokit/openapi-types": { "node_modules/@octokit/auth-oauth-user/node_modules/@octokit/openapi-types": {
"version": "22.2.0", "version": "22.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
@@ -9982,6 +10044,11 @@
"@octokit/openapi-types": "^22.2.0" "@octokit/openapi-types": "^22.2.0"
} }
}, },
"node_modules/@octokit/auth-oauth-user/node_modules/universal-user-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q=="
},
"node_modules/@octokit/auth-token": { "node_modules/@octokit/auth-token": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
@@ -10035,38 +10102,32 @@
"@octokit/openapi-types": "^24.2.0" "@octokit/openapi-types": "^24.2.0"
} }
}, },
"node_modules/@octokit/core/node_modules/universal-user-agent": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==",
"license": "ISC"
},
"node_modules/@octokit/endpoint": { "node_modules/@octokit/endpoint": {
"version": "10.1.4", "version": "9.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.4.tgz", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
"integrity": "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==", "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^14.0.0", "@octokit/types": "^13.1.0",
"universal-user-agent": "^7.0.2" "universal-user-agent": "^6.0.0"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": { "node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": {
"version": "25.1.0", "version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@octokit/endpoint/node_modules/@octokit/types": { "node_modules/@octokit/endpoint/node_modules/@octokit/types": {
"version": "14.1.0", "version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^25.1.0" "@octokit/openapi-types": "^24.2.0"
} }
}, },
"node_modules/@octokit/graphql": { "node_modules/@octokit/graphql": {
@@ -10098,12 +10159,6 @@
"@octokit/openapi-types": "^24.2.0" "@octokit/openapi-types": "^24.2.0"
} }
}, },
"node_modules/@octokit/graphql/node_modules/universal-user-agent": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==",
"license": "ISC"
},
"node_modules/@octokit/oauth-authorization-url": { "node_modules/@octokit/oauth-authorization-url": {
"version": "7.1.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz",
@@ -10126,6 +10181,18 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/@octokit/oauth-methods/node_modules/@octokit/endpoint": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz",
"integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==",
"dependencies": {
"@octokit/types": "^13.0.0",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/oauth-methods/node_modules/@octokit/openapi-types": { "node_modules/@octokit/oauth-methods/node_modules/@octokit/openapi-types": {
"version": "22.2.0", "version": "22.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
@@ -10164,6 +10231,11 @@
"@octokit/openapi-types": "^22.2.0" "@octokit/openapi-types": "^22.2.0"
} }
}, },
"node_modules/@octokit/oauth-methods/node_modules/universal-user-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q=="
},
"node_modules/@octokit/openapi-types": { "node_modules/@octokit/openapi-types": {
"version": "19.1.0", "version": "19.1.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz",
@@ -10304,54 +10376,31 @@
} }
}, },
"node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": { "node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": {
"version": "24.2.0", "version": "22.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg=="
"license": "MIT"
}, },
"node_modules/@octokit/request-error/node_modules/@octokit/types": { "node_modules/@octokit/request-error/node_modules/@octokit/types": {
"version": "13.10.0", "version": "13.6.1",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.6.1.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", "integrity": "sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^24.2.0" "@octokit/openapi-types": "^22.2.0"
}
},
"node_modules/@octokit/request/node_modules/@octokit/endpoint": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
} }
}, },
"node_modules/@octokit/request/node_modules/@octokit/openapi-types": { "node_modules/@octokit/request/node_modules/@octokit/openapi-types": {
"version": "24.2.0", "version": "22.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg=="
"license": "MIT"
}, },
"node_modules/@octokit/request/node_modules/@octokit/types": { "node_modules/@octokit/request/node_modules/@octokit/types": {
"version": "13.10.0", "version": "13.6.1",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.6.1.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", "integrity": "sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^24.2.0" "@octokit/openapi-types": "^22.2.0"
} }
}, },
"node_modules/@octokit/request/node_modules/universal-user-agent": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==",
"license": "ISC"
},
"node_modules/@octokit/rest": { "node_modules/@octokit/rest": {
"version": "20.0.2", "version": "20.0.2",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.0.2.tgz", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.0.2.tgz",
@@ -18239,8 +18288,7 @@
"node_modules/fast-content-type-parse": { "node_modules/fast-content-type-parse": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz",
"integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==", "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ=="
"license": "MIT"
}, },
"node_modules/fast-copy": { "node_modules/fast-copy": {
"version": "3.0.1", "version": "3.0.1",
@@ -24728,12 +24776,6 @@
"jsonwebtoken": "^9.0.2" "jsonwebtoken": "^9.0.2"
} }
}, },
"node_modules/octokit-auth-probot/node_modules/universal-user-agent": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==",
"license": "ISC"
},
"node_modules/odbc": { "node_modules/odbc": {
"version": "2.4.9", "version": "2.4.9",
"resolved": "https://registry.npmjs.org/odbc/-/odbc-2.4.9.tgz", "resolved": "https://registry.npmjs.org/odbc/-/odbc-2.4.9.tgz",
@@ -30663,10 +30705,9 @@
"integrity": "sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ==" "integrity": "sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ=="
}, },
"node_modules/universal-user-agent": { "node_modules/universal-user-agent": {
"version": "7.0.3", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="
"license": "ISC"
}, },
"node_modules/universalify": { "node_modules/universalify": {
"version": "2.0.1", "version": "2.0.1",

View File

@@ -158,7 +158,6 @@
"@octokit/core": "^5.2.1", "@octokit/core": "^5.2.1",
"@octokit/plugin-paginate-graphql": "^4.0.1", "@octokit/plugin-paginate-graphql": "^4.0.1",
"@octokit/plugin-retry": "^5.0.5", "@octokit/plugin-retry": "^5.0.5",
"@octokit/request": "8.4.1",
"@octokit/rest": "^20.0.2", "@octokit/rest": "^20.0.2",
"@octokit/webhooks-types": "^7.3.1", "@octokit/webhooks-types": "^7.3.1",
"@octopusdeploy/api-client": "^3.4.1", "@octopusdeploy/api-client": "^3.4.1",

View File

@@ -1,19 +0,0 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasColumn(TableName.Reminder, "fromDate"))) {
await knex.schema.alterTable(TableName.Reminder, (t) => {
t.timestamp("fromDate", { useTz: true }).nullable();
});
}
}
export async function down(knex: Knex): Promise<void> {
if (await knex.schema.hasColumn(TableName.Reminder, "fromDate")) {
await knex.schema.alterTable(TableName.Reminder, (t) => {
t.dropColumn("fromDate");
});
}
}

View File

@@ -14,8 +14,7 @@ export const RemindersSchema = z.object({
repeatDays: z.number().nullable().optional(), repeatDays: z.number().nullable().optional(),
nextReminderDate: z.date(), nextReminderDate: z.date(),
createdAt: z.date(), createdAt: z.date(),
updatedAt: z.date(), updatedAt: z.date()
fromDate: z.date().nullable().optional()
}); });
export type TReminders = z.infer<typeof RemindersSchema>; export type TReminders = z.infer<typeof RemindersSchema>;

View File

@@ -1,10 +1,8 @@
// weird commonjs-related error in the CI requires us to do the import like this // weird commonjs-related error in the CI requires us to do the import like this
import knex from "knex"; import knex from "knex";
import { v4 as uuidv4 } from "uuid";
import { TDbClient } from "@app/db"; import { TDbClient } from "@app/db";
import { TableName, TAuditLogs } from "@app/db/schemas"; import { TableName, TAuditLogs } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { DatabaseError, GatewayTimeoutError } from "@app/lib/errors"; import { DatabaseError, GatewayTimeoutError } from "@app/lib/errors";
import { ormify, selectAllTableCols, TOrmify } from "@app/lib/knex"; import { ormify, selectAllTableCols, TOrmify } from "@app/lib/knex";
import { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
@@ -152,7 +150,6 @@ export const auditLogDALFactory = (db: TDbClient) => {
// delete all audit log that have expired // delete all audit log that have expired
const pruneAuditLog: TAuditLogDALFactory["pruneAuditLog"] = async (tx) => { const pruneAuditLog: TAuditLogDALFactory["pruneAuditLog"] = async (tx) => {
const runPrune = async (dbClient: knex.Knex) => {
const AUDIT_LOG_PRUNE_BATCH_SIZE = 10000; const AUDIT_LOG_PRUNE_BATCH_SIZE = 10000;
const MAX_RETRY_ON_FAILURE = 3; const MAX_RETRY_ON_FAILURE = 3;
@@ -164,7 +161,7 @@ export const auditLogDALFactory = (db: TDbClient) => {
logger.info(`${QueueName.DailyResourceCleanUp}: audit log started`); logger.info(`${QueueName.DailyResourceCleanUp}: audit log started`);
do { do {
try { try {
const findExpiredLogSubQuery = dbClient(TableName.AuditLog) const findExpiredLogSubQuery = (tx || db)(TableName.AuditLog)
.where("expiresAt", "<", today) .where("expiresAt", "<", today)
.where("createdAt", "<", today) // to use audit log partition .where("createdAt", "<", today) // to use audit log partition
.orderBy(`${TableName.AuditLog}.createdAt`, "desc") .orderBy(`${TableName.AuditLog}.createdAt`, "desc")
@@ -172,7 +169,7 @@ export const auditLogDALFactory = (db: TDbClient) => {
.limit(AUDIT_LOG_PRUNE_BATCH_SIZE); .limit(AUDIT_LOG_PRUNE_BATCH_SIZE);
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
deletedAuditLogIds = await dbClient(TableName.AuditLog) deletedAuditLogIds = await (tx || db)(TableName.AuditLog)
.whereIn("id", findExpiredLogSubQuery) .whereIn("id", findExpiredLogSubQuery)
.del() .del()
.returning("id"); .returning("id");
@@ -191,31 +188,5 @@ export const auditLogDALFactory = (db: TDbClient) => {
logger.info(`${QueueName.DailyResourceCleanUp}: audit log completed`); logger.info(`${QueueName.DailyResourceCleanUp}: audit log completed`);
}; };
if (tx) { return { ...auditLogOrm, pruneAuditLog, find };
await runPrune(tx);
} else {
const QUERY_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
await db.transaction(async (trx) => {
await trx.raw(`SET statement_timeout = ${QUERY_TIMEOUT_MS}`);
await runPrune(trx);
});
}
};
const create: TAuditLogDALFactory["create"] = async (tx) => {
const config = getConfig();
if (config.DISABLE_AUDIT_LOG_STORAGE) {
return {
...tx,
id: uuidv4(),
createdAt: new Date(),
updatedAt: new Date()
};
}
return auditLogOrm.create(tx);
};
return { ...auditLogOrm, create, pruneAuditLog, find };
}; };

View File

@@ -49,7 +49,6 @@ const baseSecretScanningDataSourceQuery = ({
db.ref("encryptedCredentials").withSchema(TableName.AppConnection).as("connectionEncryptedCredentials"), db.ref("encryptedCredentials").withSchema(TableName.AppConnection).as("connectionEncryptedCredentials"),
db.ref("description").withSchema(TableName.AppConnection).as("connectionDescription"), db.ref("description").withSchema(TableName.AppConnection).as("connectionDescription"),
db.ref("version").withSchema(TableName.AppConnection).as("connectionVersion"), db.ref("version").withSchema(TableName.AppConnection).as("connectionVersion"),
db.ref("gatewayId").withSchema(TableName.AppConnection).as("connectionGatewayId"),
db.ref("createdAt").withSchema(TableName.AppConnection).as("connectionCreatedAt"), db.ref("createdAt").withSchema(TableName.AppConnection).as("connectionCreatedAt"),
db.ref("updatedAt").withSchema(TableName.AppConnection).as("connectionUpdatedAt"), db.ref("updatedAt").withSchema(TableName.AppConnection).as("connectionUpdatedAt"),
db db
@@ -83,7 +82,6 @@ const expandSecretScanningDataSource = <
connectionUpdatedAt, connectionUpdatedAt,
connectionVersion, connectionVersion,
connectionIsPlatformManagedCredentials, connectionIsPlatformManagedCredentials,
connectionGatewayId,
...el ...el
} = dataSource; } = dataSource;
@@ -102,8 +100,7 @@ const expandSecretScanningDataSource = <
createdAt: connectionCreatedAt, createdAt: connectionCreatedAt,
updatedAt: connectionUpdatedAt, updatedAt: connectionUpdatedAt,
version: connectionVersion, version: connectionVersion,
isPlatformManagedCredentials: connectionIsPlatformManagedCredentials, isPlatformManagedCredentials: connectionIsPlatformManagedCredentials
gatewayId: connectionGatewayId
} }
: undefined : undefined
}; };

View File

@@ -59,7 +59,6 @@ const envSchema = z
AUDIT_LOGS_DB_ROOT_CERT: zpStr( AUDIT_LOGS_DB_ROOT_CERT: zpStr(
z.string().describe("Postgres database base64-encoded CA cert for Audit logs").optional() z.string().describe("Postgres database base64-encoded CA cert for Audit logs").optional()
), ),
DISABLE_AUDIT_LOG_STORAGE: zodStrBool.default("false").optional().describe("Disable audit log storage"),
MAX_LEASE_LIMIT: z.coerce.number().default(10000), MAX_LEASE_LIMIT: z.coerce.number().default(10000),
DB_ROOT_CERT: zpStr(z.string().describe("Postgres database base64-encoded CA cert").optional()), DB_ROOT_CERT: zpStr(z.string().describe("Postgres database base64-encoded CA cert").optional()),
DB_HOST: zpStr(z.string().describe("Postgres database host").optional()), DB_HOST: zpStr(z.string().describe("Postgres database host").optional()),
@@ -483,15 +482,6 @@ export const overwriteSchema: {
fields: { key: keyof TEnvConfig; description?: string }[]; fields: { key: keyof TEnvConfig; description?: string }[];
}; };
} = { } = {
auditLogs: {
name: "Audit Logs",
fields: [
{
key: "DISABLE_AUDIT_LOG_STORAGE",
description: "Disable audit log storage"
}
]
},
aws: { aws: {
name: "AWS", name: "AWS",
fields: [ fields: [

View File

@@ -2144,8 +2144,7 @@ export const registerRoutes = async (
inviteOnlySignup: z.boolean().optional(), inviteOnlySignup: z.boolean().optional(),
redisConfigured: z.boolean().optional(), redisConfigured: z.boolean().optional(),
secretScanningConfigured: z.boolean().optional(), secretScanningConfigured: z.boolean().optional(),
samlDefaultOrgSlug: z.string().optional(), samlDefaultOrgSlug: z.string().optional()
auditLogStorageDisabled: z.boolean().optional()
}) })
} }
}, },
@@ -2172,8 +2171,7 @@ export const registerRoutes = async (
inviteOnlySignup: Boolean(serverCfg.allowSignUp), inviteOnlySignup: Boolean(serverCfg.allowSignUp),
redisConfigured: cfg.isRedisConfigured, redisConfigured: cfg.isRedisConfigured,
secretScanningConfigured: cfg.isSecretScanningConfigured, secretScanningConfigured: cfg.isSecretScanningConfigured,
samlDefaultOrgSlug: cfg.samlDefaultOrgSlug, samlDefaultOrgSlug: cfg.samlDefaultOrgSlug
auditLogStorageDisabled: Boolean(cfg.DISABLE_AUDIT_LOG_STORAGE)
}; };
} }
}); });

View File

@@ -22,7 +22,6 @@ export const registerSecretReminderRouter = async (server: FastifyZodProvider) =
message: z.string().trim().max(1024).optional(), message: z.string().trim().max(1024).optional(),
repeatDays: z.number().min(1).nullable().optional(), repeatDays: z.number().min(1).nullable().optional(),
nextReminderDate: z.string().datetime().nullable().optional(), nextReminderDate: z.string().datetime().nullable().optional(),
fromDate: z.string().datetime().nullable().optional(),
recipients: z.string().array().optional() recipients: z.string().array().optional()
}) })
.refine((data) => { .refine((data) => {
@@ -46,7 +45,6 @@ export const registerSecretReminderRouter = async (server: FastifyZodProvider) =
message: req.body.message, message: req.body.message,
repeatDays: req.body.repeatDays, repeatDays: req.body.repeatDays,
nextReminderDate: req.body.nextReminderDate, nextReminderDate: req.body.nextReminderDate,
fromDate: req.body.fromDate,
recipients: req.body.recipients recipients: req.body.recipients
} }
}); });

View File

@@ -1,5 +1,4 @@
import { createAppAuth } from "@octokit/auth-app"; import { createAppAuth } from "@octokit/auth-app";
import { request } from "@octokit/request";
import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios";
import https from "https"; import https from "https";
import RE2 from "re2"; import RE2 from "re2";
@@ -13,6 +12,7 @@ import { GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway";
import { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
import { getAppConnectionMethodName } from "@app/services/app-connection/app-connection-fns"; import { getAppConnectionMethodName } from "@app/services/app-connection/app-connection-fns";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
import { AppConnection } from "../app-connection-enums"; import { AppConnection } from "../app-connection-enums";
import { GitHubConnectionMethod } from "./github-connection-enums"; import { GitHubConnectionMethod } from "./github-connection-enums";
@@ -30,23 +30,6 @@ export const getGitHubConnectionListItem = () => {
}; };
}; };
export const getGitHubInstanceApiUrl = async (config: {
credentials: Pick<TGitHubConnectionConfig["credentials"], "host" | "instanceType">;
}) => {
const host = config.credentials.host || "github.com";
await blockLocalAndPrivateIpAddresses(host);
let apiBase: string;
if (config.credentials.instanceType === "server") {
apiBase = `${host}/api/v3`;
} else {
apiBase = `api.${host}`;
}
return apiBase;
};
export const requestWithGitHubGateway = async <T>( export const requestWithGitHubGateway = async <T>(
appConnection: { gatewayId?: string | null }, appConnection: { gatewayId?: string | null },
gatewayService: Pick<TGatewayServiceFactory, "fnGetGatewayClientTlsByGatewayId">, gatewayService: Pick<TGatewayServiceFactory, "fnGetGatewayClientTlsByGatewayId">,
@@ -90,10 +73,7 @@ export const requestWithGitHubGateway = async <T>(
return await httpRequest.request(finalRequestConfig); return await httpRequest.request(finalRequestConfig);
} catch (error) { } catch (error) {
const axiosError = error as AxiosError; const axiosError = error as AxiosError;
logger.error( logger.error("Error during GitHub gateway request:", axiosError.message, axiosError.response?.data);
{ message: axiosError.message, data: axiosError.response?.data },
"Error during GitHub gateway request:"
);
throw error; throw error;
} }
}, },
@@ -132,10 +112,7 @@ export const getGitHubAppAuthToken = async (appConnection: TGitHubConnection) =>
const appAuth = createAppAuth({ const appAuth = createAppAuth({
appId, appId,
privateKey: appPrivateKey, privateKey: appPrivateKey,
installationId: appConnection.credentials.installationId, installationId: appConnection.credentials.installationId
request: request.defaults({
baseUrl: `https://${await getGitHubInstanceApiUrl(appConnection)}`
})
}); });
const { token } = await appAuth({ type: "installation" }); const { token } = await appAuth({ type: "installation" });
@@ -164,7 +141,7 @@ export const makePaginatedGitHubRequest = async <T, R = T[]>(
const token = const token =
method === GitHubConnectionMethod.OAuth ? credentials.accessToken : await getGitHubAppAuthToken(appConnection); method === GitHubConnectionMethod.OAuth ? credentials.accessToken : await getGitHubAppAuthToken(appConnection);
let url: string | null = `https://${await getGitHubInstanceApiUrl(appConnection)}${path}`; let url: string | null = `https://api.${credentials.host || "github.com"}${path}`;
let results: T[] = []; let results: T[] = [];
let i = 0; let i = 0;
@@ -348,8 +325,6 @@ export const validateGitHubConnectionCredentials = async (
}); });
} }
} catch (e: unknown) { } catch (e: unknown) {
logger.error(e, "Unable to verify GitHub connection");
if (e instanceof BadRequestError) { if (e instanceof BadRequestError) {
throw e; throw e;
} }
@@ -380,7 +355,7 @@ export const validateGitHubConnectionCredentials = async (
}; };
}[]; }[];
}>(config, gatewayService, { }>(config, gatewayService, {
url: `https://${await getGitHubInstanceApiUrl(config)}/user/installations`, url: IntegrationUrls.GITHUB_USER_INSTALLATIONS.replace("api.github.com", `api.${host}`),
headers: { headers: {
Accept: "application/json", Accept: "application/json",
Authorization: `Bearer ${tokenResp.data.access_token}`, Authorization: `Bearer ${tokenResp.data.access_token}`,
@@ -402,15 +377,11 @@ export const validateGitHubConnectionCredentials = async (
switch (method) { switch (method) {
case GitHubConnectionMethod.App: case GitHubConnectionMethod.App:
return { return {
installationId: credentials.installationId, installationId: credentials.installationId
instanceType: credentials.instanceType,
host: credentials.host
}; };
case GitHubConnectionMethod.OAuth: case GitHubConnectionMethod.OAuth:
return { return {
accessToken: tokenResp.data.access_token, accessToken: tokenResp.data.access_token
instanceType: credentials.instanceType,
host: credentials.host
}; };
default: default:
throw new InternalServerError({ throw new InternalServerError({

View File

@@ -10,59 +10,26 @@ import {
import { GitHubConnectionMethod } from "./github-connection-enums"; import { GitHubConnectionMethod } from "./github-connection-enums";
export const GitHubConnectionOAuthInputCredentialsSchema = z.union([ export const GitHubConnectionOAuthInputCredentialsSchema = z.object({
z.object({
code: z.string().trim().min(1, "OAuth code required"), code: z.string().trim().min(1, "OAuth code required"),
instanceType: z.literal("server"),
host: z.string().trim().min(1, "Host is required for server instance type")
}),
z.object({
code: z.string().trim().min(1, "OAuth code required"),
instanceType: z.literal("cloud").optional(),
host: z.string().trim().optional() host: z.string().trim().optional()
}) });
]);
export const GitHubConnectionAppInputCredentialsSchema = z.union([ export const GitHubConnectionAppInputCredentialsSchema = z.object({
z.object({
code: z.string().trim().min(1, "GitHub App code required"), code: z.string().trim().min(1, "GitHub App code required"),
installationId: z.string().min(1, "GitHub App Installation ID required"), installationId: z.string().min(1, "GitHub App Installation ID required"),
instanceType: z.literal("server"),
host: z.string().trim().min(1, "Host is required for server instance type")
}),
z.object({
code: z.string().trim().min(1, "GitHub App code required"),
installationId: z.string().min(1, "GitHub App Installation ID required"),
instanceType: z.literal("cloud").optional(),
host: z.string().trim().optional() host: z.string().trim().optional()
}) });
]);
export const GitHubConnectionOAuthOutputCredentialsSchema = z.union([ export const GitHubConnectionOAuthOutputCredentialsSchema = z.object({
z.object({
accessToken: z.string(), accessToken: z.string(),
instanceType: z.literal("server"),
host: z.string().trim().min(1)
}),
z.object({
accessToken: z.string(),
instanceType: z.literal("cloud").optional(),
host: z.string().trim().optional() host: z.string().trim().optional()
}) });
]);
export const GitHubConnectionAppOutputCredentialsSchema = z.union([ export const GitHubConnectionAppOutputCredentialsSchema = z.object({
z.object({
installationId: z.string(), installationId: z.string(),
instanceType: z.literal("server"),
host: z.string().trim().min(1)
}),
z.object({
installationId: z.string(),
instanceType: z.literal("cloud").optional(),
host: z.string().trim().optional() host: z.string().trim().optional()
}) });
]);
export const ValidateGitHubConnectionCredentialsSchema = z.discriminatedUnion("method", [ export const ValidateGitHubConnectionCredentialsSchema = z.discriminatedUnion("method", [
z.object({ z.object({
@@ -117,17 +84,11 @@ export const GitHubConnectionSchema = z.intersection(
export const SanitizedGitHubConnectionSchema = z.discriminatedUnion("method", [ export const SanitizedGitHubConnectionSchema = z.discriminatedUnion("method", [
BaseGitHubConnectionSchema.extend({ BaseGitHubConnectionSchema.extend({
method: z.literal(GitHubConnectionMethod.App), method: z.literal(GitHubConnectionMethod.App),
credentials: z.object({ credentials: GitHubConnectionAppOutputCredentialsSchema.pick({})
instanceType: z.union([z.literal("server"), z.literal("cloud")]).optional(),
host: z.string().optional()
})
}), }),
BaseGitHubConnectionSchema.extend({ BaseGitHubConnectionSchema.extend({
method: z.literal(GitHubConnectionMethod.OAuth), method: z.literal(GitHubConnectionMethod.OAuth),
credentials: z.object({ credentials: GitHubConnectionOAuthOutputCredentialsSchema.pick({})
instanceType: z.union([z.literal("server"), z.literal("cloud")]).optional(),
host: z.string().optional()
})
}) })
]); ]);

View File

@@ -15,15 +15,10 @@ export const validateAltNameField = z
.trim() .trim()
.refine( .refine(
(name) => { (name) => {
return ( return isFQDN(name, { allow_wildcard: true }) || z.string().email().safeParse(name).success || isValidIp(name);
isFQDN(name, { allow_wildcard: true, require_tld: false }) ||
z.string().url().safeParse(name).success ||
z.string().email().safeParse(name).success ||
isValidIp(name)
);
}, },
{ {
message: "SAN must be a valid hostname, email address, IP address or URL" message: "SAN must be a valid hostname, email address, or IP address"
} }
); );
@@ -44,15 +39,10 @@ export const validateAltNamesField = z
if (data === "") return true; if (data === "") return true;
// Split and validate each alt name // Split and validate each alt name
return data.split(", ").every((name) => { return data.split(", ").every((name) => {
return ( return isFQDN(name, { allow_wildcard: true }) || z.string().email().safeParse(name).success || isValidIp(name);
isFQDN(name, { allow_wildcard: true, require_tld: false }) ||
z.string().url().safeParse(name).success ||
z.string().email().safeParse(name).success ||
isValidIp(name)
);
}); });
}, },
{ {
message: "Each alt name must be a valid hostname, email address, IP address or URL" message: "Each alt name must be a valid hostname or email address"
} }
); );

View File

@@ -152,7 +152,7 @@ export const InternalCertificateAuthorityFns = ({
extensions.push(extendedKeyUsagesExtension); extensions.push(extendedKeyUsagesExtension);
} }
let altNamesArray: { type: "email" | "dns" | "ip" | "url"; value: string }[] = []; let altNamesArray: { type: "email" | "dns"; value: string }[] = [];
if (subscriber.subjectAlternativeNames?.length) { if (subscriber.subjectAlternativeNames?.length) {
altNamesArray = subscriber.subjectAlternativeNames.map((altName) => { altNamesArray = subscriber.subjectAlternativeNames.map((altName) => {
@@ -160,18 +160,10 @@ export const InternalCertificateAuthorityFns = ({
return { type: "email", value: altName }; return { type: "email", value: altName };
} }
if (isFQDN(altName, { allow_wildcard: true, require_tld: false })) { if (isFQDN(altName, { allow_wildcard: true })) {
return { type: "dns", value: altName }; return { type: "dns", value: altName };
} }
if (z.string().url().safeParse(altName).success) {
return { type: "url", value: altName };
}
if (z.string().ip().safeParse(altName).success) {
return { type: "ip", value: altName };
}
throw new BadRequestError({ message: `Invalid SAN entry: ${altName}` }); throw new BadRequestError({ message: `Invalid SAN entry: ${altName}` });
}); });
@@ -426,7 +418,7 @@ export const InternalCertificateAuthorityFns = ({
); );
} }
let altNamesArray: { type: "email" | "dns" | "ip" | "url"; value: string }[] = []; let altNamesArray: { type: "email" | "dns"; value: string }[] = [];
if (altNames) { if (altNames) {
altNamesArray = altNames.split(",").map((altName) => { altNamesArray = altNames.split(",").map((altName) => {
@@ -434,18 +426,10 @@ export const InternalCertificateAuthorityFns = ({
return { type: "email", value: altName }; return { type: "email", value: altName };
} }
if (isFQDN(altName, { allow_wildcard: true, require_tld: false })) { if (isFQDN(altName, { allow_wildcard: true })) {
return { type: "dns", value: altName }; return { type: "dns", value: altName };
} }
if (z.string().url().safeParse(altName).success) {
return { type: "url", value: altName };
}
if (z.string().ip().safeParse(altName).success) {
return { type: "ip", value: altName };
}
throw new BadRequestError({ message: `Invalid SAN entry: ${altName}` }); throw new BadRequestError({ message: `Invalid SAN entry: ${altName}` });
}); });

View File

@@ -79,34 +79,26 @@ export const reminderServiceFactory = ({
repeatDays, repeatDays,
nextReminderDate: nextReminderDateInput, nextReminderDate: nextReminderDateInput,
recipients, recipients,
projectId, projectId
fromDate: fromDateInput
}: { }: {
secretId?: string; secretId?: string;
message?: string | null; message?: string | null;
repeatDays?: number | null; repeatDays?: number | null;
nextReminderDate?: string | null; nextReminderDate?: string | null;
recipients?: string[] | null; recipients?: string[] | null;
fromDate?: string | null;
projectId: string; projectId: string;
}) => { }) => {
if (!secretId) { if (!secretId) {
throw new BadRequestError({ message: "secretId is required" }); throw new BadRequestError({ message: "secretId is required" });
} }
let nextReminderDate; let nextReminderDate;
let fromDate;
if (nextReminderDateInput) { if (nextReminderDateInput) {
nextReminderDate = new Date(nextReminderDateInput); nextReminderDate = new Date(nextReminderDateInput);
} }
if (repeatDays) { if (repeatDays && repeatDays > 0) {
if (fromDateInput) {
fromDate = new Date(fromDateInput);
nextReminderDate = fromDate;
} else {
nextReminderDate = $addDays(repeatDays); nextReminderDate = $addDays(repeatDays);
} }
}
if (!nextReminderDate) { if (!nextReminderDate) {
throw new BadRequestError({ message: "repeatDays must be a positive number" }); throw new BadRequestError({ message: "repeatDays must be a positive number" });
@@ -120,8 +112,7 @@ export const reminderServiceFactory = ({
await reminderDAL.updateById(existingReminder.id, { await reminderDAL.updateById(existingReminder.id, {
message, message,
repeatDays, repeatDays,
nextReminderDate, nextReminderDate
fromDate
}); });
reminderId = existingReminder.id; reminderId = existingReminder.id;
} else { } else {
@@ -130,8 +121,7 @@ export const reminderServiceFactory = ({
secretId, secretId,
message, message,
repeatDays, repeatDays,
nextReminderDate, nextReminderDate
fromDate
}); });
reminderId = newReminder.id; reminderId = newReminder.id;
} }
@@ -290,29 +280,15 @@ export const reminderServiceFactory = ({
} }
const processedReminders = remindersData.map( const processedReminders = remindersData.map(
({ ({ secretId, message, repeatDays, nextReminderDate: nextReminderDateInput, recipients, projectId }) => {
secretId,
message,
repeatDays,
nextReminderDate: nextReminderDateInput,
recipients,
projectId,
fromDate: fromDateInput
}) => {
let nextReminderDate; let nextReminderDate;
let fromDate;
if (nextReminderDateInput) { if (nextReminderDateInput) {
nextReminderDate = new Date(nextReminderDateInput); nextReminderDate = new Date(nextReminderDateInput);
} }
if (repeatDays && !nextReminderDate) { if (repeatDays && repeatDays > 0 && !nextReminderDate) {
if (fromDateInput) {
fromDate = new Date(fromDateInput);
nextReminderDate = fromDate;
} else {
nextReminderDate = $addDays(repeatDays); nextReminderDate = $addDays(repeatDays);
} }
}
if (!nextReminderDate) { if (!nextReminderDate) {
throw new BadRequestError({ throw new BadRequestError({
@@ -326,19 +302,17 @@ export const reminderServiceFactory = ({
repeatDays, repeatDays,
nextReminderDate, nextReminderDate,
recipients: recipients ? [...new Set(recipients)] : [], recipients: recipients ? [...new Set(recipients)] : [],
projectId, projectId
fromDate
}; };
} }
); );
const newReminders = await reminderDAL.insertMany( const newReminders = await reminderDAL.insertMany(
processedReminders.map(({ secretId, message, repeatDays, nextReminderDate, fromDate }) => ({ processedReminders.map(({ secretId, message, repeatDays, nextReminderDate }) => ({
secretId, secretId,
message, message,
repeatDays, repeatDays,
nextReminderDate, nextReminderDate
fromDate
})), })),
tx tx
); );

View File

@@ -8,7 +8,6 @@ export type TReminder = {
message?: string | null; message?: string | null;
repeatDays?: number | null; repeatDays?: number | null;
nextReminderDate: Date; nextReminderDate: Date;
fromDate?: Date | null;
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
}; };
@@ -22,7 +21,6 @@ export type TCreateReminderDTO = {
secretId?: string; secretId?: string;
message?: string | null; message?: string | null;
repeatDays?: number | null; repeatDays?: number | null;
fromDate?: string | null;
nextReminderDate?: string | null; nextReminderDate?: string | null;
recipients?: string[] | null; recipients?: string[] | null;
}; };
@@ -33,7 +31,6 @@ export type TBatchCreateReminderDTO = {
message?: string | null; message?: string | null;
repeatDays?: number | null; repeatDays?: number | null;
nextReminderDate?: string | Date | null; nextReminderDate?: string | Date | null;
fromDate?: Date | null;
recipients?: string[] | null; recipients?: string[] | null;
projectId?: string; projectId?: string;
}[]; }[];
@@ -98,7 +95,6 @@ export interface TReminderServiceFactory {
nextReminderDate?: string | null; nextReminderDate?: string | null;
recipients?: string[] | null; recipients?: string[] | null;
projectId: string; projectId: string;
fromDate?: string | null;
}) => Promise<{ }) => Promise<{
id: string; id: string;
created: boolean; created: boolean;

View File

@@ -3,7 +3,6 @@ import sodium from "libsodium-wrappers";
import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
import { import {
getGitHubAppAuthToken, getGitHubAppAuthToken,
getGitHubInstanceApiUrl,
GitHubConnectionMethod, GitHubConnectionMethod,
makePaginatedGitHubRequest, makePaginatedGitHubRequest,
requestWithGitHubGateway requestWithGitHubGateway
@@ -74,7 +73,7 @@ const getPublicKey = async (
} }
const response = await requestWithGitHubGateway<TGitHubPublicKey>(connection, gatewayService, { const response = await requestWithGitHubGateway<TGitHubPublicKey>(connection, gatewayService, {
url: `https://${await getGitHubInstanceApiUrl(connection)}${path}`, url: `https://api.${connection.credentials.host || "github.com"}${path}`,
method: "GET", method: "GET",
headers: { headers: {
Accept: "application/vnd.github+json", Accept: "application/vnd.github+json",
@@ -112,7 +111,7 @@ const deleteSecret = async (
} }
await requestWithGitHubGateway(connection, gatewayService, { await requestWithGitHubGateway(connection, gatewayService, {
url: `https://${await getGitHubInstanceApiUrl(connection)}${path}`, url: `https://api.${connection.credentials.host || "github.com"}${path}`,
method: "DELETE", method: "DELETE",
headers: { headers: {
Accept: "application/vnd.github+json", Accept: "application/vnd.github+json",
@@ -158,7 +157,7 @@ const putSecret = async (
} }
await requestWithGitHubGateway(connection, gatewayService, { await requestWithGitHubGateway(connection, gatewayService, {
url: `https://${await getGitHubInstanceApiUrl(connection)}${path}`, url: `https://api.${connection.credentials.host || "github.com"}${path}`,
method: "PUT", method: "PUT",
headers: { headers: {
Accept: "application/vnd.github+json", Accept: "application/vnd.github+json",

View File

@@ -30,7 +30,6 @@ const baseSecretSyncQuery = ({ filter, db, tx }: { db: TDbClient; filter?: Secre
db.ref("encryptedCredentials").withSchema(TableName.AppConnection).as("connectionEncryptedCredentials"), db.ref("encryptedCredentials").withSchema(TableName.AppConnection).as("connectionEncryptedCredentials"),
db.ref("description").withSchema(TableName.AppConnection).as("connectionDescription"), db.ref("description").withSchema(TableName.AppConnection).as("connectionDescription"),
db.ref("version").withSchema(TableName.AppConnection).as("connectionVersion"), db.ref("version").withSchema(TableName.AppConnection).as("connectionVersion"),
db.ref("gatewayId").withSchema(TableName.AppConnection).as("connectionGatewayId"),
db.ref("createdAt").withSchema(TableName.AppConnection).as("connectionCreatedAt"), db.ref("createdAt").withSchema(TableName.AppConnection).as("connectionCreatedAt"),
db.ref("updatedAt").withSchema(TableName.AppConnection).as("connectionUpdatedAt"), db.ref("updatedAt").withSchema(TableName.AppConnection).as("connectionUpdatedAt"),
db db
@@ -66,7 +65,6 @@ const expandSecretSync = (
connectionUpdatedAt, connectionUpdatedAt,
connectionVersion, connectionVersion,
connectionIsPlatformManagedCredentials, connectionIsPlatformManagedCredentials,
connectionGatewayId,
...el ...el
} = secretSync; } = secretSync;
@@ -85,8 +83,7 @@ const expandSecretSync = (
createdAt: connectionCreatedAt, createdAt: connectionCreatedAt,
updatedAt: connectionUpdatedAt, updatedAt: connectionUpdatedAt,
version: connectionVersion, version: connectionVersion,
isPlatformManagedCredentials: connectionIsPlatformManagedCredentials, isPlatformManagedCredentials: connectionIsPlatformManagedCredentials
gatewayId: connectionGatewayId
}, },
folder: folder folder: folder
? { ? {

View File

@@ -1,9 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface AccessApprovalRequestTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface AccessApprovalRequestTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
projectName: string; projectName: string;
@@ -40,15 +38,18 @@ export const AccessApprovalRequestTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
You have a new access approval request pending review for the project <strong>{projectName}</strong> You have a new access approval request pending review for the project <strong>{projectName}</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]"> <Text className="text-black text-[14px] leading-[24px]">
<strong>{requesterFullName}</strong> (<BaseLink href={`mailto:${requesterEmail}`}>{requesterEmail}</BaseLink>) <strong>{requesterFullName}</strong> (
has requested {isTemporary ? "temporary" : "permanent"} access to <strong>{secretPath}</strong> in the{" "} <Link href={`mailto:${requesterEmail}`} className="text-slate-700 no-underline">
{requesterEmail}
</Link>
) has requested {isTemporary ? "temporary" : "permanent"} access to <strong>{secretPath}</strong> in the{" "}
<strong>{environment}</strong> environment. <strong>{environment}</strong> environment.
</Text> </Text>
{isTemporary && ( {isTemporary && (
<Text className="text-[14px] text-red-600 leading-[24px]"> <Text className="text-[14px] text-red-500 leading-[24px]">
<strong>This access will expire {expiresIn} after approval.</strong> <strong>This access will expire {expiresIn} after approval.</strong>
</Text> </Text>
)} )}
@@ -66,8 +67,13 @@ export const AccessApprovalRequestTemplate = ({
</Text> </Text>
)} )}
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={approvalUrl}>Review Request</BaseButton> <Button
href={approvalUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Review Request
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,18 +0,0 @@
import { Button } from "@react-email/components";
import React from "react";
type Props = {
href: string;
children: string;
};
export const BaseButton = ({ href, children }: Props) => {
return (
<Button
href={href}
className="rounded-[8px] py-[12px] px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
{children}
</Button>
);
};

View File

@@ -16,21 +16,23 @@ export const BaseEmailWrapper = ({ title, preview, children, siteUrl }: BaseEmai
<Body className="bg-gray-300 my-auto mx-auto font-sans px-[8px] py-[4px]"> <Body className="bg-gray-300 my-auto mx-auto font-sans px-[8px] py-[4px]">
<Preview>{preview}</Preview> <Preview>{preview}</Preview>
<Container className="bg-white rounded-xl my-[40px] mx-auto pb-[0px] max-w-[500px]"> <Container className="bg-white rounded-xl my-[40px] mx-auto pb-[0px] max-w-[500px]">
<Section className="mb-[24px] px-[24px] mt-[24px]"> <Section className="border-0 border-b border-[#d1e309] border-solid bg-[#EBF852] mb-[44px] h-[10px] rounded-t-xl" />
<Section className="px-[32px] mb-[18px]">
<Section className="w-[48px] h-[48px] border border-solid border-gray-300 rounded-full bg-gray-100 mx-auto">
<Img <Img
src="https://infisical.com/_next/image?url=%2Fimages%2Flogo-black.png&w=64&q=75" src={`https://infisical.com/_next/image?url=%2Fimages%2Flogo-black.png&w=64&q=75`}
width="36" width="32"
alt="Infisical Logo" alt="Infisical Logo"
className="mx-auto" className="mx-auto"
/> />
</Section> </Section>
<Hr className=" mb-[32px] mt-[0px] h-[1px]" /> </Section>
<Section className="px-[28px]">{children}</Section> <Section className="px-[28px]">{children}</Section>
<Hr className=" mt-[32px] mb-[0px] h-[1px]" /> <Hr className=" mt-[32px] mb-[0px] h-[1px]" />
<Section className="px-[24px] text-center"> <Section className="px-[24px] text-center">
<Text className="text-gray-500 text-[12px]"> <Text className="text-gray-500 text-[12px]">
Email sent via{" "} Email sent via{" "}
<Link href={siteUrl} className="text-slate-700 underline decoration-slate-700"> <Link href={siteUrl} className="text-slate-700 no-underline">
Infisical Infisical
</Link> </Link>
</Text> </Text>

View File

@@ -1,15 +0,0 @@
import { Link } from "@react-email/components";
import React from "react";
type Props = {
href: string;
children: string;
};
export const BaseLink = ({ href, children }: Props) => {
return (
<Link href={href} className="text-slate-700 underline decoration-slate-700">
{children}
</Link>
);
};

View File

@@ -1,8 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface EmailMfaTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface EmailMfaTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
code: string; code: string;
@@ -26,7 +25,11 @@ export const EmailMfaTemplate = ({ code, siteUrl, isCloud }: EmailMfaTemplatePro
<strong>Not you?</strong>{" "} <strong>Not you?</strong>{" "}
{isCloud ? ( {isCloud ? (
<> <>
Contact us at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink> immediately Contact us at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>{" "}
immediately
</> </>
) : ( ) : (
"Contact your administrator immediately" "Contact your administrator immediately"

View File

@@ -1,8 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface EmailVerificationTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface EmailVerificationTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
code: string; code: string;
@@ -30,7 +29,10 @@ export const EmailVerificationTemplate = ({ code, siteUrl, isCloud }: EmailVerif
<strong>Questions about Infisical?</strong>{" "} <strong>Questions about Infisical?</strong>{" "}
{isCloud ? ( {isCloud ? (
<> <>
Email us at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink> Email us at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
</> </>
) : ( ) : (
"Contact your administrator" "Contact your administrator"

View File

@@ -1,8 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface ExternalImportFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface ExternalImportFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
error: string; error: string;
@@ -22,9 +21,12 @@ export const ExternalImportFailedTemplate = ({ error, siteUrl, provider }: Exter
</Text> </Text>
<Text className="text-black text-[14px] leading-[24px]"> <Text className="text-black text-[14px] leading-[24px]">
If your issue persists, you can contact the Infisical team at{" "} If your issue persists, you can contact the Infisical team at{" "}
<BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink>. <Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
.
</Text> </Text>
<Text className="text-[14px] text-red-600 leading-[24px]"> <Text className="text-[14px] text-red-500 leading-[24px]">
<strong>Error:</strong> "{error}" <strong>Error:</strong> "{error}"
</Text> </Text>
</Section> </Section>

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface IntegrationSyncFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface IntegrationSyncFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -31,7 +30,7 @@ export const IntegrationSyncFailedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>{count}</strong> integration(s) failed to sync <strong>{count}</strong> integration(s) failed to sync
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<strong>Project</strong> <strong>Project</strong>
<Text className="text-[14px] mt-[4px]">{projectName}</Text> <Text className="text-[14px] mt-[4px]">{projectName}</Text>
<strong>Environment</strong> <strong>Environment</strong>
@@ -39,10 +38,15 @@ export const IntegrationSyncFailedTemplate = ({
<strong>Secret Path</strong> <strong>Secret Path</strong>
<Text className="text-[14px] mt-[4px]">{secretPath}</Text> <Text className="text-[14px] mt-[4px]">{secretPath}</Text>
<strong className="text-black">Failure Reason:</strong> <strong className="text-black">Failure Reason:</strong>
<Text className="text-[14px] mt-[4px] text-red-600 leading-[24px]">"{syncMessage}"</Text> <Text className="text-[14px] mt-[4px] text-red-500 leading-[24px]">"{syncMessage}"</Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={integrationUrl}>View Integrations</BaseButton> <Button
href={integrationUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View Integrations
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,8 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface NewDeviceLoginTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface NewDeviceLoginTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
email: string; email: string;
@@ -43,7 +42,9 @@ export const NewDeviceLoginTemplate = ({
<Text className="mb-[0px]"> <Text className="mb-[0px]">
If you believe that this login is suspicious, please contact{" "} If you believe that this login is suspicious, please contact{" "}
{isCloud ? ( {isCloud ? (
<BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink> <Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
) : ( ) : (
"your administrator" "your administrator"
)}{" "} )}{" "}

View File

@@ -1,8 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface OrgAdminBreakglassAccessTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface OrgAdminBreakglassAccessTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
email: string; email: string;
@@ -36,7 +35,10 @@ export const OrgAdminBreakglassAccessTemplate = ({
<Text className="text-[14px] mt-[4px]">{userAgent}</Text> <Text className="text-[14px] mt-[4px]">{userAgent}</Text>
<Text className="text-[14px]"> <Text className="text-[14px]">
If you'd like to disable Admin SSO Bypass, please visit{" "} If you'd like to disable Admin SSO Bypass, please visit{" "}
<BaseLink href={`${siteUrl}/organization/settings`}>Organization Security Settings</BaseLink>. <Link href={`${siteUrl}/organization/settings`} className="text-slate-700 no-underline">
Organization Security Settings
</Link>
.
</Text> </Text>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>

View File

@@ -2,7 +2,6 @@ import { Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface OrgAdminProjectGrantAccessTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview"> { interface OrgAdminProjectGrantAccessTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview"> {
email: string; email: string;
@@ -25,8 +24,8 @@ export const OrgAdminProjectGrantAccessTemplate = ({
</Heading> </Heading>
<Section className="px-[24px] mt-[36px] pt-[24px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[24px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px] mt-[4px]"> <Text className="text-[14px] mt-[4px]">
The organization admin <BaseLink href={`mailto:${email}`}>{email}</BaseLink> has self-issued direct access to The organization admin <strong>{email}</strong> has self-issued direct access to the project{" "}
the project <strong>{projectName}</strong>. <strong>{projectName}</strong>.
</Text> </Text>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>

View File

@@ -1,9 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface OrganizationInvitationTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> { interface OrganizationInvitationTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> {
metadata?: string; metadata?: string;
@@ -38,13 +36,15 @@ export const OrganizationInvitationTemplate = ({
<br /> <br />
<strong>{organizationName}</strong> on <strong>Infisical</strong> <strong>{organizationName}</strong> on <strong>Infisical</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]"> <Text className="text-black text-[14px] leading-[24px]">
{inviterFirstName && inviterUsername ? ( {inviterFirstName && inviterUsername ? (
<> <>
<strong>{inviterFirstName}</strong> ( <strong>{inviterFirstName}</strong> (
<BaseLink href={`mailto:${inviterUsername}`}>{inviterUsername}</BaseLink>) has invited you to collaborate <Link href={`mailto:${inviterUsername}`} className="text-slate-700 no-underline">
on <strong>{organizationName}</strong>. {inviterUsername}
</Link>
) has invited you to collaborate on <strong>{organizationName}</strong>.
</> </>
) : ( ) : (
<> <>
@@ -53,12 +53,13 @@ export const OrganizationInvitationTemplate = ({
)} )}
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton <Button
href={`${callback_url}?token=${token}${metadata ? `&metadata=${metadata}` : ""}&to=${encodeURIComponent(email)}&organization_id=${organizationId}`} href={`${callback_url}?token=${token}${metadata ? `&metadata=${metadata}` : ""}&to=${encodeURIComponent(email)}&organization_id=${organizationId}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
> >
Accept Invite Accept Invite
</BaseButton> </Button>
</Section> </Section>
<Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800"> <Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800">
<Text className="mb-[0px]"> <Text className="mb-[0px]">

View File

@@ -1,9 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface PasswordResetTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface PasswordResetTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
email: string; email: string;
@@ -22,13 +20,16 @@ export const PasswordResetTemplate = ({ email, isCloud, siteUrl, callback_url, t
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>Account Recovery</strong> <strong>Account Recovery</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">A password reset was requested for your Infisical account.</Text> <Text className="text-[14px]">A password reset was requested for your Infisical account.</Text>
<Text className="text-[14px]"> <Text className="text-[14px]">
If you did not initiate this request, please contact{" "} If you did not initiate this request, please contact{" "}
{isCloud ? ( {isCloud ? (
<> <>
us immediately at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink> us immediately at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
</> </>
) : ( ) : (
"your administrator immediately" "your administrator immediately"
@@ -36,8 +37,13 @@ export const PasswordResetTemplate = ({ email, isCloud, siteUrl, callback_url, t
. .
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={`${callback_url}?token=${token}&to=${encodeURIComponent(email)}`}>Reset Password</BaseButton> <Button
href={`${callback_url}?token=${token}&to=${encodeURIComponent(email)}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Reset Password
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,8 +1,6 @@
import { Button, Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseLink } from "@app/services/smtp/emails/BaseLink";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface PasswordSetupTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface PasswordSetupTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -18,16 +16,19 @@ export const PasswordSetupTemplate = ({ email, isCloud, siteUrl, callback_url, t
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>Password Setup</strong> <strong>Password Setup</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">Someone requested to set up a password for your Infisical account.</Text> <Text className="text-[14px]">Someone requested to set up a password for your Infisical account.</Text>
<Text className="text-[14px] text-red-600"> <Text className="text-[14px] text-red-500">
Make sure you are already logged in to Infisical in the current browser before clicking the link below. Make sure you are already logged in to Infisical in the current browser before clicking the link below.
</Text> </Text>
<Text className="text-[14px]"> <Text className="text-[14px]">
If you did not initiate this request, please contact{" "} If you did not initiate this request, please contact{" "}
{isCloud ? ( {isCloud ? (
<> <>
us immediately at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink> us immediately at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
</> </>
) : ( ) : (
"your administrator immediately" "your administrator immediately"
@@ -35,7 +36,7 @@ export const PasswordSetupTemplate = ({ email, isCloud, siteUrl, callback_url, t
. .
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<Button <Button
href={`${callback_url}?token=${token}&to=${encodeURIComponent(email)}`} href={`${callback_url}?token=${token}&to=${encodeURIComponent(email)}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium" className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"

View File

@@ -1,9 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface ProjectAccessRequestTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface ProjectAccessRequestTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
projectName: string; projectName: string;
@@ -32,17 +30,26 @@ export const ProjectAccessRequestTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
A user has requested access to the project <strong>{projectName}</strong> A user has requested access to the project <strong>{projectName}</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]"> <Text className="text-black text-[14px] leading-[24px]">
<strong>{requesterName}</strong> (<BaseLink href={`mailto:${requesterEmail}`}>{requesterEmail}</BaseLink>) has <strong>{requesterName}</strong> (
requested access to the project <strong>{projectName}</strong> in the organization <strong>{orgName}</strong>. <Link href={`mailto:${requesterEmail}`} className="text-slate-700 no-underline">
{requesterEmail}
</Link>
) has requested access to the project <strong>{projectName}</strong> in the organization{" "}
<strong>{orgName}</strong>.
</Text> </Text>
<Text className="text-[14px] text-slate-700 leading-[24px]"> <Text className="text-[14px] text-slate-700 leading-[24px]">
<strong className="text-black">User note:</strong> "{note}" <strong className="text-black">User note:</strong> "{note}"
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={callback_url}>Grant Access</BaseButton> <Button
href={callback_url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Grant Access
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface ProjectInvitationTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> { interface ProjectInvitationTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> {
@@ -19,13 +18,18 @@ export const ProjectInvitationTemplate = ({ callback_url, workspaceName, siteUrl
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
You've been invited to join a project on Infisical You've been invited to join a project on Infisical
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]"> <Text className="text-black text-[14px] leading-[24px]">
You've been invited to join the project <strong>{workspaceName}</strong>. You've been invited to join the project <strong>{workspaceName}</strong>.
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={callback_url}>Join Project</BaseButton> <Button
href={callback_url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Join Project
</Button>
</Section> </Section>
<Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800"> <Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800">
<Text className="mb-[0px]"> <Text className="mb-[0px]">

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface ScimUserProvisionedTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> { interface ScimUserProvisionedTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> {
@@ -25,13 +24,18 @@ export const ScimUserProvisionedTemplate = ({
<br /> <br />
<strong>{organizationName}</strong> on <strong>Infisical</strong> <strong>{organizationName}</strong> on <strong>Infisical</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]"> <Text className="text-black text-[14px] leading-[24px]">
You've been invited to collaborate on <strong>{organizationName}</strong>. You've been invited to collaborate on <strong>{organizationName}</strong>.
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={callback_url}>Accept Invite</BaseButton> <Button
href={callback_url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Accept Invite
</Button>
</Section> </Section>
<Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800"> <Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800">
<Text className="mb-[0px]"> <Text className="mb-[0px]">

View File

@@ -1,9 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface SecretApprovalRequestBypassedTemplateProps interface SecretApprovalRequestBypassedTemplateProps
extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -37,10 +35,13 @@ export const SecretApprovalRequestBypassedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
A secret approval request has been bypassed in the project <strong>{projectName}</strong> A secret approval request has been bypassed in the project <strong>{projectName}</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]"> <Text className="text-black text-[14px] leading-[24px]">
<strong>{requesterFullName}</strong> (<BaseLink href={`mailto:${requesterEmail}`}>{requesterEmail}</BaseLink>) <strong>{requesterFullName}</strong> (
has {requestType === "change" ? "merged" : "accessed"} a secret {requestType === "change" ? "to" : "in"}{" "} <Link href={`mailto:${requesterEmail}`} className="text-slate-700 no-underline">
{requesterEmail}
</Link>
) has {requestType === "change" ? "merged" : "accessed"} a secret {requestType === "change" ? "to" : "in"}{" "}
<strong>{secretPath}</strong> in the <strong>{environment}</strong> environment without obtaining the required <strong>{secretPath}</strong> in the <strong>{environment}</strong> environment without obtaining the required
approval. approval.
</Text> </Text>
@@ -49,8 +50,13 @@ export const SecretApprovalRequestBypassedTemplate = ({
{bypassReason}" {bypassReason}"
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={approvalUrl}>Review Bypass</BaseButton> <Button
href={approvalUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Review Bypass
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretApprovalRequestNeedsReviewTemplateProps interface SecretApprovalRequestNeedsReviewTemplateProps
@@ -28,15 +27,20 @@ export const SecretApprovalRequestNeedsReviewTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
A secret approval request for the project <strong>{projectName}</strong> requires review A secret approval request for the project <strong>{projectName}</strong> requires review
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">Hello {firstName},</Text> <Text className="text-[14px]">Hello {firstName},</Text>
<Text className="text-black text-[14px] leading-[24px]"> <Text className="text-black text-[14px] leading-[24px]">
You have a new secret change request pending your review for the project <strong>{projectName}</strong> in the You have a new secret change request pending your review for the project <strong>{projectName}</strong> in the
organization <strong>{organizationName}</strong>. organization <strong>{organizationName}</strong>.
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={approvalUrl}>Review Changes</BaseButton> <Button
href={approvalUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Review Changes
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,9 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface SecretLeakIncidentTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface SecretLeakIncidentTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
numberOfSecrets: number; numberOfSecrets: number;
@@ -26,7 +24,7 @@ export const SecretLeakIncidentTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
Infisical has uncovered <strong>{numberOfSecrets}</strong> secret(s) from a recent commit Infisical has uncovered <strong>{numberOfSecrets}</strong> secret(s) from a recent commit
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[8px] pb-[8px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[8px] pb-[8px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]"> <Text className="text-[14px]">
You are receiving this notification because one or more leaked secrets have been detected in a recent commit You are receiving this notification because one or more leaked secrets have been detected in a recent commit
{(pusher_email || pusher_name) && ( {(pusher_email || pusher_name) && (
@@ -35,7 +33,11 @@ export const SecretLeakIncidentTemplate = ({
pushed by <strong>{pusher_name ?? "Unknown Pusher"}</strong>{" "} pushed by <strong>{pusher_name ?? "Unknown Pusher"}</strong>{" "}
{pusher_email && ( {pusher_email && (
<> <>
(<BaseLink href={`mailto:${pusher_email}`}>{pusher_email}</BaseLink>) (
<Link href={`mailto:${pusher_email}`} className="text-slate-700 no-underline">
{pusher_email}
</Link>
)
</> </>
)} )}
</> </>
@@ -47,16 +49,24 @@ export const SecretLeakIncidentTemplate = ({
a comment in the given programming language. This will prevent future notifications from being sent out for a comment in the given programming language. This will prevent future notifications from being sent out for
these secrets. these secrets.
</Text> </Text>
<Text className="text-[14px] text-red-600"> <Text className="text-[14px] text-red-500">
If these are production secrets, please rotate them immediately. If these are production secrets, please rotate them immediately.
</Text> </Text>
<Text className="text-[14px]"> <Text className="text-[14px]">
Once you have taken action, be sure to update the status of the risk in the{" "} Once you have taken action, be sure to update the status of the risk in the{" "}
<BaseLink href={`${siteUrl}/organization/secret-scanning`}>Infisical Dashboard</BaseLink>. <Link href={`${siteUrl}/organization/secret-scanning`} className="text-slate-700 no-underline">
Infisical Dashboard
</Link>
.
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={`${siteUrl}/organization/secret-scanning`}>View Leaked Secrets</BaseButton> <Button
href={`${siteUrl}/organization/secret-scanning`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View Leaked Secrets
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretRequestCompletedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface SecretRequestCompletedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -21,7 +20,7 @@ export const SecretRequestCompletedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>A secret has been shared with you</strong> <strong>A secret has been shared with you</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] text-center pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] text-center pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]"> <Text className="text-[14px]">
{respondentUsername ? <strong>{respondentUsername}</strong> : "Someone"} shared a secret{" "} {respondentUsername ? <strong>{respondentUsername}</strong> : "Someone"} shared a secret{" "}
{name && ( {name && (
@@ -32,8 +31,13 @@ export const SecretRequestCompletedTemplate = ({
with you. with you.
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={secretRequestUrl}>View Secret</BaseButton> <Button
href={secretRequestUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View Secret
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretRotationFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface SecretRotationFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -29,7 +28,7 @@ export const SecretRotationFailedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
Your <strong>{rotationType}</strong> rotation <strong>{rotationName}</strong> failed to rotate Your <strong>{rotationType}</strong> rotation <strong>{rotationName}</strong> failed to rotate
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<strong>Name</strong> <strong>Name</strong>
<Text className="text-[14px] mt-[4px]">{rotationName}</Text> <Text className="text-[14px] mt-[4px]">{rotationName}</Text>
<strong>Type</strong> <strong>Type</strong>
@@ -41,12 +40,15 @@ export const SecretRotationFailedTemplate = ({
<strong>Secret Path</strong> <strong>Secret Path</strong>
<Text className="text-[14px] mt-[4px]">{secretPath}</Text> <Text className="text-[14px] mt-[4px]">{secretPath}</Text>
<strong>Reason:</strong> <strong>Reason:</strong>
<Text className="text-[14px] text-red-600 mt-[4px]">{content}</Text> <Text className="text-[14px] text-red-500 mt-[4px]">{content}</Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={`${rotationUrl}?search=${rotationName}&secretPath=${secretPath}`}> <Button
href={`${rotationUrl}?search=${rotationName}&secretPath=${secretPath}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View in Infisical View in Infisical
</BaseButton> </Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretScanningScanFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface SecretScanningScanFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -31,7 +30,7 @@ export const SecretScanningScanFailedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
Infisical encountered an error while attempting to scan the resource <strong>{resourceName}</strong> Infisical encountered an error while attempting to scan the resource <strong>{resourceName}</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<strong>Resource</strong> <strong>Resource</strong>
<Text className="text-[14px] mt-[4px]">{resourceName}</Text> <Text className="text-[14px] mt-[4px]">{resourceName}</Text>
<strong>Data Source</strong> <strong>Data Source</strong>
@@ -41,10 +40,15 @@ export const SecretScanningScanFailedTemplate = ({
<strong>Timestamp</strong> <strong>Timestamp</strong>
<Text className="text-[14px] mt-[4px]">{timestamp}</Text> <Text className="text-[14px] mt-[4px]">{timestamp}</Text>
<strong>Error</strong> <strong>Error</strong>
<Text className="text-[14px] text-red-600 mt-[4px]">{errorMessage}</Text> <Text className="text-[14px] text-red-500 mt-[4px]">{errorMessage}</Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={url}>View in Infisical</BaseButton> <Button
href={url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View in Infisical
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,9 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface SecretScanningSecretsDetectedTemplateProps interface SecretScanningSecretsDetectedTemplateProps
extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -34,7 +32,7 @@ export const SecretScanningSecretsDetectedTemplate = ({
Infisical has uncovered <strong>{numberOfSecrets}</strong> secret(s) Infisical has uncovered <strong>{numberOfSecrets}</strong> secret(s)
{isDiffScan ? " from a recent commit to" : " in"} <strong>{resourceName}</strong> {isDiffScan ? " from a recent commit to" : " in"} <strong>{resourceName}</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[8px] pb-[8px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[8px] pb-[8px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]"> <Text className="text-[14px]">
You are receiving this notification because one or more leaked secrets have been detected You are receiving this notification because one or more leaked secrets have been detected
{isDiffScan && " in a recent commit"} {isDiffScan && " in a recent commit"}
@@ -45,7 +43,11 @@ export const SecretScanningSecretsDetectedTemplate = ({
pushed by <strong>{authorName ?? "Unknown Pusher"}</strong>{" "} pushed by <strong>{authorName ?? "Unknown Pusher"}</strong>{" "}
{authorEmail && ( {authorEmail && (
<> <>
(<BaseLink href={`mailto:${authorEmail}`}>{authorEmail}</BaseLink>) (
<Link href={`mailto:${authorEmail}`} className="text-slate-700 no-underline">
{authorEmail}
</Link>
)
</> </>
)} )}
</> </>
@@ -63,16 +65,24 @@ export const SecretScanningSecretsDetectedTemplate = ({
a comment in the given programming language. This will prevent future notifications from being sent out for a comment in the given programming language. This will prevent future notifications from being sent out for
these secrets. these secrets.
</Text> </Text>
<Text className="text-[14px] text-red-600"> <Text className="text-[14px] text-red-500">
If these are production secrets, please rotate them immediately. If these are production secrets, please rotate them immediately.
</Text> </Text>
<Text className="text-[14px]"> <Text className="text-[14px]">
Once you have taken action, be sure to update the finding status in the{" "} Once you have taken action, be sure to update the finding status in the{" "}
<BaseLink href={url}>Infisical Dashboard</BaseLink>. <Link href={url} className="text-slate-700 no-underline">
Infisical Dashboard
</Link>
.
</Text> </Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={url}>View Leaked Secrets</BaseButton> <Button
href={url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View Leaked Secrets
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretSyncFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface SecretSyncFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -29,7 +28,7 @@ export const SecretSyncFailedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
Your <strong>{syncDestination}</strong> sync <strong>{syncName}</strong> failed to complete Your <strong>{syncDestination}</strong> sync <strong>{syncName}</strong> failed to complete
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<strong>Name</strong> <strong>Name</strong>
<Text className="text-[14px] mt-[4px]">{syncName}</Text> <Text className="text-[14px] mt-[4px]">{syncName}</Text>
<strong>Destination</strong> <strong>Destination</strong>
@@ -51,12 +50,17 @@ export const SecretSyncFailedTemplate = ({
{failureMessage && ( {failureMessage && (
<> <>
<strong>Reason:</strong> <strong>Reason:</strong>
<Text className="text-[14px] text-red-600 mt-[4px]">{failureMessage}</Text> <Text className="text-[14px] text-red-500 mt-[4px]">{failureMessage}</Text>
</> </>
)} )}
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={syncUrl}>View in Infisical</BaseButton> <Button
href={syncUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View in Infisical
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface ServiceTokenExpiryNoticeTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface ServiceTokenExpiryNoticeTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -25,15 +24,20 @@ export const ServiceTokenExpiryNoticeTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>Service token expiry notice</strong> <strong>Service token expiry notice</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]"> <Text className="text-[14px]">
Your service token <strong>{tokenName}</strong> for the project <strong>{projectName}</strong> will expire Your service token <strong>{tokenName}</strong> for the project <strong>{projectName}</strong> will expire
within 24 hours. within 24 hours.
</Text> </Text>
<Text>If this token is still needed for your workflow, please create a new one before it expires.</Text> <Text>If this token is still needed for your workflow, please create a new one before it expires.</Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={url}>Create New Token</BaseButton> <Button
href={url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Create New Token
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -1,8 +1,7 @@
import { Heading, Section, Text } from "@react-email/components"; import { Heading, Link, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface SignupEmailVerificationTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface SignupEmailVerificationTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
code: string; code: string;
@@ -30,7 +29,10 @@ export const SignupEmailVerificationTemplate = ({ code, siteUrl, isCloud }: Sign
<strong>Questions about setting up Infisical?</strong>{" "} <strong>Questions about setting up Infisical?</strong>{" "}
{isCloud ? ( {isCloud ? (
<> <>
Email us at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink> Email us at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
</> </>
) : ( ) : (
"Contact your administrator" "Contact your administrator"

View File

@@ -1,7 +1,6 @@
import { Heading, Section, Text } from "@react-email/components"; import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react"; import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper"; import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface UnlockAccountTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> { interface UnlockAccountTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -19,14 +18,19 @@ export const UnlockAccountTemplate = ({ token, siteUrl, callback_url }: UnlockAc
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0"> <Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>Unlock your Infisical account</strong> <strong>Unlock your Infisical account</strong>
</Heading> </Heading>
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50"> <Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]"> <Text className="text-[14px]">
Your account has been temporarily locked due to multiple failed login attempts. Your account has been temporarily locked due to multiple failed login attempts.
</Text> </Text>
<Text>If these attempts were not made by you, reset your password immediately.</Text> <Text>If these attempts were not made by you, reset your password immediately.</Text>
</Section> </Section>
<Section className="text-center"> <Section className="text-center mt-[28px]">
<BaseButton href={`${callback_url}?token=${token}`}>Unlock Account</BaseButton> <Button
href={`${callback_url}?token=${token}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Unlock Account
</Button>
</Section> </Section>
</BaseEmailWrapper> </BaseEmailWrapper>
); );

View File

@@ -105,13 +105,10 @@ The templates hold an array of templates that will be rendered and injected into
### Authentication ### Authentication
The Infisical Agent Injector supports Machine Identity [Kubernetes Auth](/documentation/platform/identities/kubernetes-auth) and [LDAP Auth](/documentation/platform/identities/ldap-auth) authentication. The Infisical Agent Injector only supports Machine Identity [Kubernetes Auth](/documentation/platform/identities/kubernetes-auth) authentication at the moment.
<AccordionGroup>
<Accordion title="Kubernetes Auth">
To configure Kubernetes Auth, you need to set the `auth.type` field to `kubernetes` and set the `auth.config.identity-id` to the ID of the machine identity you wish to use for authentication. To configure Kubernetes Auth, you need to set the `auth.type` field to `kubernetes` and set the `auth.config.identity-id` to the ID of the machine identity you wish to use for authentication.
```yaml ```yaml
auth: auth:
type: "kubernetes" type: "kubernetes"
@@ -147,52 +144,6 @@ The Infisical Agent Injector supports Machine Identity [Kubernetes Auth](/docume
kubectl apply -f config-map.yaml kubectl apply -f config-map.yaml
``` ```
</Accordion>
<Accordion title="LDAP Auth">
To configure LDAP Auth, you need to set the `auth.type` field to `ldap-auth` and set the `auth.config.identity-id` to the ID of the machine identity you wish to use for authentication. Configure the `auth.config.username` and `auth.config.password` to the username and password of the LDAP user to authenticate with.
```yaml
auth:
type: "ldap-auth"
config:
identity-id: "<your-infisical-machine-identity-id>"
username: "<your-ldap-username>"
password: "<your-ldap-password>"
```
### Example ConfigMap
```yaml config-map.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-config-map
data:
config.yaml: |
infisical:
address: "https://app.infisical.com"
auth:
type: "ldap-auth"
config:
identity-id: "<your-infisical-machine-identity-id>"
username: "<your-ldap-username>"
password: "<your-ldap-password>"
templates:
- destination-path: "/path/to/save/secrets/file.txt"
template-content: |
{{- with secret "<your-project-id>" "dev" "/" }}
{{- range . }}
{{ .Key }}={{ .Value }}
{{- end }}
{{- end }}
```
```bash
kubectl apply -f config-map.yaml
```
</Accordion>
</AccordionGroup>
To use the config map in your pod, you will need to add the `org.infisical.com/agent-config-map` annotation to your pod's deployment. The value of the annotation is the name of the config map you created above. To use the config map in your pod, you will need to add the `org.infisical.com/agent-config-map` annotation to your pod's deployment. The value of the annotation is the name of the config map you created above.
```yaml ```yaml
apiVersion: v1 apiVersion: v1

View File

@@ -68,6 +68,11 @@ spec:
serviceAccountKeyFilePath: </path-to-service-account-key-file.json> serviceAccountKeyFilePath: </path-to-service-account-key-file.json>
gcpIdTokenAuth: gcpIdTokenAuth:
identityId: <machine-identity-id> identityId: <machine-identity-id>
ldapAuth:
identityId: <machine-identity-id>
credentialsRef:
secretName: <secret-name> # ldap-auth-credentials
secretNamespace: <secret-namespace> # default
kubernetesAuth: kubernetesAuth:
identityId: <machine-identity-id> identityId: <machine-identity-id>
serviceAccountRef: serviceAccountRef:
@@ -137,6 +142,7 @@ When `hostAPI` is not defined the operator fetches secrets from Infisical Cloud.
<Note> <Note>
The lease duration at most be 1 day (24 hours). And the TTL must be less than the max TTL defined on the dynamic secret. The lease duration at most be 1 day (24 hours). And the TTL must be less than the max TTL defined on the dynamic secret.
</Note> </Note>
</Accordion> </Accordion>
@@ -300,7 +306,6 @@ The available authentication methods are `universalAuth`, `kubernetesAuth`, `aws
- `autoCreateServiceAccountToken`: If set to `true`, the operator will automatically create a short-lived service account token on-demand for the service account. Defaults to `false`. - `autoCreateServiceAccountToken`: If set to `true`, the operator will automatically create a short-lived service account token on-demand for the service account. Defaults to `false`.
- `serviceAccountTokenAudiences`: Optionally specify audience for the service account token. This field is only relevant if you have set `autoCreateServiceAccountToken` to `true`. No audience is specified by default. - `serviceAccountTokenAudiences`: Optionally specify audience for the service account token. This field is only relevant if you have set `autoCreateServiceAccountToken` to `true`. No audience is specified by default.
Example: Example:
```yaml ```yaml
@@ -316,7 +321,40 @@ The available authentication methods are `universalAuth`, `kubernetesAuth`, `aws
``` ```
</Accordion> </Accordion>
<Accordion title="ldapAuth">
The LDAP machine identity authentication method is used to authenticate with a configured LDAP directory. [Read more about LDAP Auth](/documentation/platform/identities/ldap-auth).
Valid fields:
- `identityId`: The identity ID of the machine identity you created.
- `credentialsRef`: The name and namespace of the Kubernetes secret that stores the LDAP credentials.
- `credentialsRef.secretName`: The name of the Kubernetes secret.
- `credentialsRef.secretNamespace`: The namespace of the Kubernetes secret.
Example:
```yaml
# infisical-push-secret.yaml
spec:
ldapAuth:
identityId: <machine-identity-id>
credentialsRef:
secretName: <secret-name>
secretNamespace: <secret-namespace>
```
```yaml
# machine-identity-credentials.yaml
apiVersion: v1
kind: Secret
metadata:
name: ldap-auth-credentials
type: Opaque
stringData:
username: <ldap-username>
password: <ldap-password>
```
</Accordion>
<Accordion title="awsIamAuth"> <Accordion title="awsIamAuth">
The AWS IAM machine identity authentication method is used to authenticate with Infisical. The AWS IAM machine identity authentication method is used to authenticate with Infisical.
[Read more about AWS IAM Auth](/documentation/platform/identities/aws-auth). [Read more about AWS IAM Auth](/documentation/platform/identities/aws-auth).

View File

@@ -70,6 +70,11 @@ Before applying the InfisicalPushSecret CRD, you need to create a Kubernetes sec
serviceAccountRef: serviceAccountRef:
name: <secret-name> name: <secret-name>
namespace: <secret-namespace> namespace: <secret-namespace>
ldapAuth:
identityId: <machine-identity-id>
credentialsRef:
secretName: <secret-name> # ldap-auth-credentials
secretNamespace: <secret-namespace> # default
universalAuth: universalAuth:
credentialsRef: credentialsRef:
secretName: <secret-name> # universal-auth-credentials secretName: <secret-name> # universal-auth-credentials
@@ -324,7 +329,39 @@ After applying the InfisicalPushSecret CRD, you should notice that the secrets y
namespace: <secret-namespace> namespace: <secret-namespace>
``` ```
</Accordion> </Accordion>
<Accordion title="ldapAuth">
The LDAP machine identity authentication method is used to authenticate with a configured LDAP directory. [Read more about LDAP Auth](/documentation/platform/identities/ldap-auth).
Valid fields:
- `identityId`: The identity ID of the machine identity you created.
- `credentialsRef`: The name and namespace of the Kubernetes secret that stores the LDAP credentials.
- `credentialsRef.secretName`: The name of the Kubernetes secret.
- `credentialsRef.secretNamespace`: The namespace of the Kubernetes secret.
Example:
```yaml
# infisical-push-secret.yaml
spec:
ldapAuth:
identityId: <machine-identity-id>
credentialsRef:
secretName: <secret-name>
secretNamespace: <secret-namespace>
```
```yaml
# machine-identity-credentials.yaml
apiVersion: v1
kind: Secret
metadata:
name: ldap-auth-credentials
type: Opaque
stringData:
username: <ldap-username>
password: <ldap-password>
```
</Accordion>
<Accordion title="awsIamAuth"> <Accordion title="awsIamAuth">
The AWS IAM machine identity authentication method is used to authenticate with Infisical. The AWS IAM machine identity authentication method is used to authenticate with Infisical.
[Read more about AWS IAM Auth](/documentation/platform/identities/aws-auth). [Read more about AWS IAM Auth](/documentation/platform/identities/aws-auth).

View File

@@ -525,49 +525,6 @@ spec:
... ...
``` ```
</Tab> </Tab>
</Tabs> </Tabs>
@@ -747,6 +704,59 @@ spec:
</Accordion> </Accordion>
<Accordion title="authentication.ldapAuth">
The LDAP machine identity authentication method is used to authenticate with Infisical using the configured LDAP directory. The username and password needs to be stored in a Kubernetes secret. This block defines the reference to the name and namespace of secret that stores these credentials.
<Steps>
<Step title="Create a machine identity">
You need to create a machine identity, and give it access to the project(s) you want to interact with. You can [read more about machine identities here](/documentation/platform/identities/universal-auth).
</Step>
<Step title="Create Kubernetes secret containing machine identity credentials">
Once you have created your machine identity and added it to your project(s), you will need to create a Kubernetes secret containing the identity credentials.
To quickly create a Kubernetes secret containing the identity credentials, you can run the command below.
Make sure you replace `<your-identity-ldap-username>` with the identity LDAP username and `<your-identity-ldap-password>` with the identity LDAP password.
``` bash
kubectl create secret generic ldap-auth-credentials --from-literal=username="<your-identity-ldap-username>" --from-literal=password="<your-identity-ldap-password>"
```
</Step>
<Step title="Add reference for the Kubernetes secret containing the identity credentials">
Once the secret is created, add the `secretName` and `secretNamespace` of the secret that was just created under `authentication.ldapAuth.credentialsRef` field in the InfisicalSecret resource.
</Step>
</Steps>
<Info>
Make sure to also populate the `secretsScope` field with the project slug
_`projectSlug`_, environment slug _`envSlug`_, and secrets path
_`secretsPath`_ that you want to fetch secrets from. Please see the example
below.
</Info>
## Example
```yaml
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
name: infisicalsecret-sample-crd
spec:
authentication:
ldapAuth:
secretsScope:
projectSlug: <project-slug> # <-- project slug
envSlug: <env-slug> # "dev", "staging", "prod", etc..
secretsPath: "<secrets-path>" # Root is "/"
identityId: <machine-identity-id>
credentialsRef:
secretName: ldap-auth-credentials # <-- name of the Kubernetes secret that stores our machine identity credentials
secretNamespace: default # <-- namespace of the Kubernetes secret that stores our machine identity credentials
```
</Accordion>
<Accordion title="authentication.serviceToken"> <Accordion title="authentication.serviceToken">
The service token required to authenticate with Infisical needs to be stored in a Kubernetes secret. This block defines the reference to the name and namespace of secret that stores this service token. The service token required to authenticate with Infisical needs to be stored in a Kubernetes secret. This block defines the reference to the name and namespace of secret that stores this service token.
@@ -928,7 +938,9 @@ The properties includes defining the name and namespace of the Kubernetes config
The Infisical operator will automatically create the Kubernetes config map in the specified name/namespace and ensure it stays up-to-date. If a config map already exists in the specified namespace, the operator will update the existing config map with the new data. The Infisical operator will automatically create the Kubernetes config map in the specified name/namespace and ensure it stays up-to-date. If a config map already exists in the specified namespace, the operator will update the existing config map with the new data.
<Warning> <Warning>
The usage of config maps is only intended for storing non-sensitive data. If you are looking to store sensitive data, please use the [managed secret](#operator-managed-secrets) property instead. The usage of config maps is only intended for storing non-sensitive data. If
you are looking to store sensitive data, please use the [managed
secret](#operator-managed-secrets) property instead.
</Warning> </Warning>
<Accordion title="managedKubeConfigMapReferences"> <Accordion title="managedKubeConfigMapReferences">
@@ -955,7 +967,6 @@ The Infisical operator will automatically create the Kubernetes config map in th
</Accordion> </Accordion>
#### Managed ConfigMap Templating #### Managed ConfigMap Templating
Fetching secrets from Infisical as is via the operator may not be enough. This is where templating functionality may be helpful. Fetching secrets from Infisical as is via the operator may not be enough. This is where templating functionality may be helpful.
@@ -1025,6 +1036,7 @@ Using Go templates, you can format, combine, and create new key-value pairs from
### Available templating functions ### Available templating functions
Please refer to the [templating functions documentation](/integrations/platforms/kubernetes/overview#available-helper-functions) for more information. Please refer to the [templating functions documentation](/integrations/platforms/kubernetes/overview#available-helper-functions) for more information.
</Accordion> </Accordion>
## Applying CRD ## Applying CRD
@@ -1061,8 +1073,6 @@ To verify that the operator has successfully created the managed secret, you can
</Tab> </Tab>
</Tabs> </Tabs>
## Using Managed Secret In Your Deployment ## Using Managed Secret In Your Deployment
To make use of the managed secret created by the operator into your deployment can be achieved through several methods. To make use of the managed secret created by the operator into your deployment can be achieved through several methods.
@@ -1150,6 +1160,7 @@ Here, we will highlight three of the most common ways to utilize it. Learn more
ports: ports:
- containerPort: 80 - containerPort: 80
``` ```
</Accordion> </Accordion>
<Accordion title="volumes"> <Accordion title="volumes">
@@ -1339,9 +1350,11 @@ secrets.infisical.com/auto-reload: "true"
</Accordion> </Accordion>
<Info> <Info>
#### How it works #### How it works When a managed secret is updated, the operator checks for
When a managed secret is updated, the operator checks for any Deployments, DaemonSets, or StatefulSets that consume the updated secret and have the annotation any Deployments, DaemonSets, or StatefulSets that consume the updated secret
`secrets.infisical.com/auto-reload: "true"`. For each matching workload, the operator triggers a rolling restart to ensure it picks up the latest secret values. and have the annotation `secrets.infisical.com/auto-reload: "true"`. For each
matching workload, the operator triggers a rolling restart to ensure it picks
up the latest secret values.
</Info> </Info>
## Using Managed ConfigMap In Your Deployment ## Using Managed ConfigMap In Your Deployment
@@ -1350,10 +1363,10 @@ To make use of the managed ConfigMap created by the operator into your deploymen
Here, we will highlight three of the most common ways to utilize it. Learn more about Kubernetes ConfigMaps [here](https://kubernetes.io/docs/concepts/configuration/configmap/) Here, we will highlight three of the most common ways to utilize it. Learn more about Kubernetes ConfigMaps [here](https://kubernetes.io/docs/concepts/configuration/configmap/)
<Tip> <Tip>
Automatic redeployment of deployments using managed ConfigMaps is not yet supported. Automatic redeployment of deployments using managed ConfigMaps is not yet
supported.
</Tip> </Tip>
<Accordion title="envFrom"> <Accordion title="envFrom">
This will take all the secrets from your managed ConfigMap and expose them to your container This will take all the secrets from your managed ConfigMap and expose them to your container
@@ -1490,6 +1503,7 @@ Here, we will highlight three of the most common ways to utilize it. Learn more
configMap: configMap:
name: managed-configmap # <- managed configmap name: managed-configmap # <- managed configmap
``` ```
</Accordion> </Accordion>
The definition file of the Kubernetes secret for the CA certificate can be structured like the following: The definition file of the Kubernetes secret for the CA certificate can be structured like the following:
@@ -1548,4 +1562,5 @@ Thus, if a specific label is required on the resulting secret, it can be applied
namespace: default namespace: default
type: Opaque type: Opaque
``` ```
</Accordion> </Accordion>

View File

@@ -65,14 +65,7 @@ Example values:
default="false" default="false"
optional optional
> >
Determines whether your Infisical instance can automatically read the service Determines whether your Infisical instance can automatically read the service account token of the pod it's running on. Used for features such as the IRSA auth method.
account token of the pod it's running on. Used for features such as the IRSA
auth method.
</ParamField>
<ParamField query="DISABLE_AUDIT_LOG_STORAGE" type="string" default="false">
Disable storing audit logs in the database. This is useful if you're using
audit log streams and don't want to store them in the database.
</ParamField> </ParamField>
## CORS ## CORS

View File

@@ -35,7 +35,6 @@ export type TServerConfig = {
initialized: boolean; initialized: boolean;
allowSignUp: boolean; allowSignUp: boolean;
allowedSignUpDomain?: string | null; allowedSignUpDomain?: string | null;
disableAuditLogStorage: boolean;
isMigrationModeOn?: boolean; isMigrationModeOn?: boolean;
trustSamlEmails: boolean; trustSamlEmails: boolean;
trustLdapEmails: boolean; trustLdapEmails: boolean;

View File

@@ -11,7 +11,6 @@ export type TGitHubConnection = TRootAppConnection & { app: AppConnection.GitHub
method: GitHubConnectionMethod.OAuth; method: GitHubConnectionMethod.OAuth;
credentials: { credentials: {
code: string; code: string;
instanceType?: "cloud" | "server";
host?: string; host?: string;
}; };
} }
@@ -20,7 +19,6 @@ export type TGitHubConnection = TRootAppConnection & { app: AppConnection.GitHub
credentials: { credentials: {
code: string; code: string;
installationId: string; installationId: string;
instanceType?: "cloud" | "server";
host?: string; host?: string;
}; };
} }

View File

@@ -12,15 +12,14 @@ export const useCreateReminder = (secretId: string) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation<Reminder, object, CreateReminderDTO>({ return useMutation<Reminder, object, CreateReminderDTO>({
mutationFn: async ({ message, repeatDays, nextReminderDate, recipients, fromDate }) => { mutationFn: async ({ message, repeatDays, nextReminderDate, recipients }) => {
const { data } = await apiRequest.post<{ reminder: Reminder }>( const { data } = await apiRequest.post<{ reminder: Reminder }>(
`/api/v1/reminders/secrets/${secretId}`, `/api/v1/reminders/secrets/${secretId}`,
{ {
message, message,
repeatDays, repeatDays,
nextReminderDate, nextReminderDate,
recipients, recipients
fromDate
} }
); );
return data.reminder; return data.reminder;

View File

@@ -2,7 +2,6 @@ export type CreateReminderDTO = {
message?: string | null; message?: string | null;
repeatDays?: number | null; repeatDays?: number | null;
nextReminderDate?: Date | null; nextReminderDate?: Date | null;
fromDate?: Date | null;
secretId: string; secretId: string;
recipients?: string[]; recipients?: string[];
}; };

View File

@@ -5,5 +5,4 @@ export type ServerStatus = {
secretScanningConfigured: boolean; secretScanningConfigured: boolean;
redisConfigured: boolean; redisConfigured: boolean;
samlDefaultOrgSlug: string; samlDefaultOrgSlug: string;
auditLogStorageDisabled: boolean;
}; };

View File

@@ -6,11 +6,10 @@ import { twMerge } from "tailwind-merge";
import { CreateOrgModal } from "@app/components/organization/CreateOrgModal"; import { CreateOrgModal } from "@app/components/organization/CreateOrgModal";
import { Banner } from "@app/components/page-frames/Banner"; import { Banner } from "@app/components/page-frames/Banner";
import { useServerConfig, useSubscription } from "@app/context"; import { useServerConfig } from "@app/context";
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { useFetchServerStatus } from "@app/hooks/api"; import { useFetchServerStatus } from "@app/hooks/api";
import { AuditLogBanner } from "./components/AuditLogBanner";
import { InsecureConnectionBanner } from "./components/InsecureConnectionBanner"; import { InsecureConnectionBanner } from "./components/InsecureConnectionBanner";
import { Navbar } from "./components/NavBar"; import { Navbar } from "./components/NavBar";
import { OrgSidebar } from "./components/OrgSidebar"; import { OrgSidebar } from "./components/OrgSidebar";
@@ -32,7 +31,6 @@ export const OrganizationLayout = () => {
const containerHeight = config.pageFrameContent ? "h-[94vh]" : "h-screen"; const containerHeight = config.pageFrameContent ? "h-[94vh]" : "h-screen";
const { data: serverDetails, isLoading } = useFetchServerStatus(); const { data: serverDetails, isLoading } = useFetchServerStatus();
const { subscription } = useSubscription();
return ( return (
<> <>
@@ -43,7 +41,6 @@ export const OrganizationLayout = () => {
<Navbar /> <Navbar />
{!isLoading && !serverDetails?.redisConfigured && <RedisBanner />} {!isLoading && !serverDetails?.redisConfigured && <RedisBanner />}
{!isLoading && !serverDetails?.emailConfigured && <SmtpBanner />} {!isLoading && !serverDetails?.emailConfigured && <SmtpBanner />}
{!isLoading && subscription.auditLogs && <AuditLogBanner />}
{!window.isSecureContext && <InsecureConnectionBanner />} {!window.isSecureContext && <InsecureConnectionBanner />}
<div className="flex flex-grow flex-col overflow-y-hidden md:flex-row"> <div className="flex flex-grow flex-col overflow-y-hidden md:flex-row">
<OrgSidebar isHidden={isInsideProject} /> <OrgSidebar isHidden={isInsideProject} />

View File

@@ -1,23 +0,0 @@
import { useOrganization } from "@app/context";
import { useFetchServerStatus, useGetAuditLogStreams } from "@app/hooks/api";
import { OrgAlertBanner } from "../OrgAlertBanner";
export const AuditLogBanner = () => {
const org = useOrganization();
const { data: status, isLoading: isLoadingStatus } = useFetchServerStatus();
const { data: streams, isLoading: isLoadingStreams } = useGetAuditLogStreams(org.currentOrg.id);
if (isLoadingStreams || isLoadingStatus || !streams) return null;
if (status?.auditLogStorageDisabled && !streams.length) {
return (
<OrgAlertBanner
text="Attention: Audit logs storage is disabled but no audit log streams have been configured."
link="https://infisical.com/docs/documentation/platform/audit-log-streams/audit-log-streams"
/>
);
}
return null;
};

View File

@@ -1 +0,0 @@
export * from "./AuditLogBanner";

View File

@@ -48,16 +48,9 @@ const formSchema = genericAppConnectionFieldsSchema.extend({
app: z.literal(AppConnection.GitHub), app: z.literal(AppConnection.GitHub),
method: z.nativeEnum(GitHubConnectionMethod), method: z.nativeEnum(GitHubConnectionMethod),
credentials: z credentials: z
.union([ .object({
z.object({
instanceType: z.literal("cloud").optional(),
host: z.string().optional() host: z.string().optional()
}),
z.object({
instanceType: z.literal("server"),
host: z.string().min(1, "Required")
}) })
])
.optional() .optional()
}); });
@@ -77,10 +70,7 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
defaultValues: appConnection ?? { defaultValues: appConnection ?? {
app: AppConnection.GitHub, app: AppConnection.GitHub,
method: GitHubConnectionMethod.App, method: GitHubConnectionMethod.App,
gatewayId: null, gatewayId: null
credentials: {
instanceType: "cloud"
}
} }
}); });
@@ -88,7 +78,6 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
handleSubmit, handleSubmit,
control, control,
watch, watch,
setValue,
formState: { isSubmitting, isDirty } formState: { isSubmitting, isDirty }
} = form; } = form;
@@ -96,7 +85,6 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list()); const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list());
const selectedMethod = watch("method"); const selectedMethod = watch("method");
const instanceType = watch("credentials.instanceType");
const onSubmit = (formData: FormData) => { const onSubmit = (formData: FormData) => {
setIsRedirecting(true); setIsRedirecting(true);
@@ -115,7 +103,7 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
switch (formData.method) { switch (formData.method) {
case GitHubConnectionMethod.App: case GitHubConnectionMethod.App:
window.location.assign( window.location.assign(
`${githubHost}/${formData.credentials?.instanceType === "server" ? "github-apps" : "apps"}/${appClientSlug}/installations/new?state=${state}` `${githubHost}/apps/${appClientSlug}/installations/new?state=${state}`
); );
break; break;
case GitHubConnectionMethod.OAuth: case GitHubConnectionMethod.OAuth:
@@ -187,54 +175,13 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
</FormControl> </FormControl>
)} )}
/> />
{subscription.gateway && (
<Accordion type="single" collapsible className="w-full"> <Accordion type="single" collapsible className="w-full">
<AccordionItem value="enterprise-options" className="data-[state=open]:border-none"> <AccordionItem value="enterprise-options" className="data-[state=open]:border-none">
<AccordionTrigger className="h-fit flex-none pl-1 text-sm"> <AccordionTrigger className="h-fit flex-none pl-1 text-sm">
<div className="order-1 ml-3">GitHub Enterprise Options</div> <div className="order-1 ml-3">GitHub Enterprise Options</div>
</AccordionTrigger> </AccordionTrigger>
<AccordionContent childrenClassName="px-0"> <AccordionContent childrenClassName="px-0">
<Controller
name="credentials.instanceType"
control={control}
render={({ field }) => (
<FormControl label="Instance Type">
<Select
value={field.value}
onValueChange={(e) => {
field.onChange(e);
if (e === "cloud") {
setValue("gatewayId", null);
}
}}
className="w-full border border-mineshaft-500"
dropdownContainerClassName="max-w-none"
placeholder="Enterprise Cloud"
position="popper"
>
<SelectItem value="cloud">Enterprise Cloud</SelectItem>
<SelectItem value="server">Enterprise Server</SelectItem>
</Select>
</FormControl>
)}
/>
<Controller
name="credentials.host"
control={control}
shouldUnregister
render={({ field, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Instance Hostname"
isOptional={instanceType === "cloud"}
isRequired={instanceType === "server"}
>
<Input {...field} placeholder="github.com" />
</FormControl>
)}
/>
{subscription.gateway && instanceType === "server" && (
<OrgPermissionCan <OrgPermissionCan
I={OrgGatewayPermissionActions.AttachGateways} I={OrgGatewayPermissionActions.AttachGateways}
a={OrgPermissionSubjects.Gateway} a={OrgPermissionSubjects.Gateway}
@@ -243,6 +190,7 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
<Controller <Controller
control={control} control={control}
name="gatewayId" name="gatewayId"
defaultValue=""
render={({ field: { value, onChange }, fieldState: { error } }) => ( render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl <FormControl
isError={Boolean(error?.message)} isError={Boolean(error?.message)}
@@ -256,7 +204,7 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
<div> <div>
<Select <Select
isDisabled={!isAllowed} isDisabled={!isAllowed}
value={value || (null as unknown as string)} value={value as string}
onValueChange={onChange} onValueChange={onChange}
className="w-full border border-mineshaft-500" className="w-full border border-mineshaft-500"
dropdownContainerClassName="max-w-none" dropdownContainerClassName="max-w-none"
@@ -266,7 +214,7 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
> >
<SelectItem <SelectItem
value={null as unknown as string} value={null as unknown as string}
onClick={() => onChange(null)} onClick={() => onChange(undefined)}
> >
Internet Gateway Internet Gateway
</SelectItem> </SelectItem>
@@ -283,10 +231,25 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => {
/> />
)} )}
</OrgPermissionCan> </OrgPermissionCan>
<Controller
name="credentials.host"
control={control}
shouldUnregister
render={({ field, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Hostname"
isOptional
>
<Input {...field} placeholder="github.com" />
</FormControl>
)} )}
/>
</AccordionContent> </AccordionContent>
</AccordionItem> </AccordionItem>
</Accordion> </Accordion>
)}
<div className="mt-8 flex items-center"> <div className="mt-8 flex items-center">
<Button <Button
className="mr-4" className="mr-4"

View File

@@ -408,7 +408,6 @@ export const OAuthCallbackPage = () => {
credentials: { credentials: {
code: code as string, code: code as string,
installationId: installationId as string, installationId: installationId as string,
...(credentials?.instanceType && { instanceType: credentials.instanceType }),
...(credentials?.host && { host: credentials.host }) ...(credentials?.host && { host: credentials.host })
}, },
gatewayId gatewayId
@@ -417,7 +416,6 @@ export const OAuthCallbackPage = () => {
connectionId, connectionId,
credentials: { credentials: {
code: code as string, code: code as string,
...(credentials?.instanceType && { instanceType: credentials.instanceType }),
...(credentials?.host && { host: credentials.host }) ...(credentials?.host && { host: credentials.host })
}, },
gatewayId gatewayId
@@ -433,7 +431,6 @@ export const OAuthCallbackPage = () => {
method: GitHubConnectionMethod.App, method: GitHubConnectionMethod.App,
credentials: { credentials: {
code: code as string, code: code as string,
...(credentials?.instanceType && { instanceType: credentials.instanceType }),
installationId: installationId as string, installationId: installationId as string,
...(credentials?.host && { host: credentials.host }) ...(credentials?.host && { host: credentials.host })
}, },
@@ -443,7 +440,6 @@ export const OAuthCallbackPage = () => {
method: GitHubConnectionMethod.OAuth, method: GitHubConnectionMethod.OAuth,
credentials: { credentials: {
code: code as string, code: code as string,
...(credentials?.instanceType && { instanceType: credentials.instanceType }),
...(credentials?.host && { host: credentials.host }) ...(credentials?.host && { host: credentials.host })
}, },
gatewayId gatewayId

View File

@@ -12,7 +12,6 @@ export const AuditLogsPage = () => {
<link rel="icon" href="/infisical.ico" /> <link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" /> <meta property="og:image" content="/images/message.png" />
</Helmet> </Helmet>
<div className="flex h-full w-full justify-center bg-bunker-800 text-white"> <div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<div className="w-full max-w-7xl"> <div className="w-full max-w-7xl">
<PageHeader <PageHeader

View File

@@ -1,5 +1,5 @@
import { Fragment } from "react"; import { Fragment } from "react";
import { faCancel, faFile } from "@fortawesome/free-solid-svg-icons"; import { faFile } from "@fortawesome/free-solid-svg-icons";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { import {
@@ -16,7 +16,7 @@ import {
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { Timezone } from "@app/helpers/datetime"; import { Timezone } from "@app/helpers/datetime";
import { useFetchServerStatus, useGetAuditLogs } from "@app/hooks/api"; import { useGetAuditLogs } from "@app/hooks/api";
import { TGetAuditLogsFilter } from "@app/hooks/api/auditLogs/types"; import { TGetAuditLogsFilter } from "@app/hooks/api/auditLogs/types";
import { LogsTableRow } from "./LogsTableRow"; import { LogsTableRow } from "./LogsTableRow";
@@ -30,8 +30,6 @@ type Props = {
const AUDIT_LOG_LIMIT = 30; const AUDIT_LOG_LIMIT = 30;
export const LogsTable = ({ filter, refetchInterval, timezone }: Props) => { export const LogsTable = ({ filter, refetchInterval, timezone }: Props) => {
const { data: status } = useFetchServerStatus();
// Determine the project ID for filtering // Determine the project ID for filtering
const filterProjectId = const filterProjectId =
// Use the projectId from the filter if it exists // Use the projectId from the filter if it exists
@@ -81,11 +79,7 @@ export const LogsTable = ({ filter, refetchInterval, timezone }: Props) => {
{isEmpty && ( {isEmpty && (
<Tr> <Tr>
<Td colSpan={3}> <Td colSpan={3}>
{status?.auditLogStorageDisabled ? (
<EmptyState title="Audit log storage is disabled" icon={faCancel} />
) : (
<EmptyState title="No audit logs on file" icon={faFile} /> <EmptyState title="No audit logs on file" icon={faFile} />
)}
</Td> </Td>
</Tr> </Tr>
)} )}

View File

@@ -52,15 +52,8 @@ export const SecretSearchInput = ({
if (activeIndex === 0 && e.key === "Enter") setIsOpen(true); if (activeIndex === 0 && e.key === "Enter") setIsOpen(true);
}} }}
autoComplete="off" autoComplete="off"
className={twMerge( className="input text-md h-[2.3rem] w-full rounded-md rounded-l-none bg-mineshaft-800 py-[0.375rem] pl-2.5 pr-8 text-gray-400 placeholder-mineshaft-50 placeholder-opacity-50 outline-none duration-200 placeholder:text-sm hover:ring-bunker-400/60 focus:bg-mineshaft-700/80 focus:ring-1 focus:ring-primary-400/50"
"input text-md h-[2.3rem] w-full rounded-md rounded-l-none bg-mineshaft-800 py-[0.375rem] pl-2.5 text-gray-400 placeholder-mineshaft-50 placeholder-opacity-50 outline-none duration-200 placeholder:text-sm hover:ring-bunker-400/60 focus:bg-mineshaft-700/80 focus:ring-1 focus:ring-primary-400/50", placeholder="Search by secret, folder, tag or metadata..."
hasSearch ? "pr-8" : "pr-2.5"
)}
placeholder={
isSingleEnv
? "Search by secret, folder, tag or metadata..."
: "Search by secret or folder name..."
}
value={value} value={value}
onChange={(e) => onChange(e.target.value)} onChange={(e) => onChange(e.target.value)}
/> />

View File

@@ -537,21 +537,17 @@ export const SecretApprovalRequestChanges = ({
<div <div
className="flex flex-nowrap items-center justify-between space-x-2 rounded border border-mineshaft-600 bg-mineshaft-800 px-2 py-1" className="flex flex-nowrap items-center justify-between space-x-2 rounded border border-mineshaft-600 bg-mineshaft-800 px-2 py-1"
key={`required-approver-${requiredApprover.userId}`} key={`required-approver-${requiredApprover.userId}`}
>
<Tooltip
content={
requiredApprover.firstName
? `${requiredApprover.firstName || ""} ${requiredApprover.lastName || ""}`
: undefined
}
position="left"
sideOffset={10}
> >
<div className="flex text-sm"> <div className="flex text-sm">
<div>{requiredApprover?.email}</div> <Tooltip
content={`${requiredApprover.firstName || ""} ${
requiredApprover.lastName || ""
}`}
>
<span>{requiredApprover?.email}</span>
</Tooltip>
<span className="text-red">*</span> <span className="text-red">*</span>
</div> </div>
</Tooltip>
<div> <div>
{reviewer?.comment && ( {reviewer?.comment && (
<Tooltip className="max-w-lg break-words" content={reviewer.comment}> <Tooltip className="max-w-lg break-words" content={reviewer.comment}>

View File

@@ -4,7 +4,6 @@ import { faClock, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useQueryClient } from "@tanstack/react-query"; import { useQueryClient } from "@tanstack/react-query";
import { format } from "date-fns";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { z } from "zod"; import { z } from "zod";
@@ -34,7 +33,6 @@ const MIN_REPEAT_DAYS = 1;
const MAX_REPEAT_DAYS = 365; const MAX_REPEAT_DAYS = 365;
const DEFAULT_REPEAT_DAYS = 30; const DEFAULT_REPEAT_DAYS = 30;
const DEFAULT_TEXTAREA_ROWS = 8; const DEFAULT_TEXTAREA_ROWS = 8;
const ONE_DAY_IN_MILLIS = 86400000;
// Enums // Enums
enum ReminderType { enum ReminderType {
@@ -81,11 +79,6 @@ const ReminderFormSchema = z.object({
.refine((data) => data > new Date(), { message: "Reminder date must be in the future" }) .refine((data) => data > new Date(), { message: "Reminder date must be in the future" })
.nullable() .nullable()
.optional(), .optional(),
fromDate: z.coerce
.date()
.refine((data) => data > new Date(), { message: "From date must be in the future" })
.nullable()
.optional(),
reminderType: z.enum(["Recurring", "One Time"]) reminderType: z.enum(["Recurring", "One Time"])
}); });
@@ -93,7 +86,7 @@ export type TReminderFormSchema = z.infer<typeof ReminderFormSchema>;
// Custom hook for form state management // Custom hook for form state management
const useReminderForm = (reminderData?: Reminder) => { const useReminderForm = (reminderData?: Reminder) => {
const { repeatDays, message, nextReminderDate, fromDate } = reminderData || {}; const { repeatDays, message, nextReminderDate } = reminderData || {};
const isEditMode = Boolean(reminderData); const isEditMode = Boolean(reminderData);
@@ -103,10 +96,9 @@ const useReminderForm = (reminderData?: Reminder) => {
message: message || "", message: message || "",
nextReminderDate: nextReminderDate || null, nextReminderDate: nextReminderDate || null,
reminderType: repeatDays ? ReminderType.Recurring : ReminderType.OneTime, reminderType: repeatDays ? ReminderType.Recurring : ReminderType.OneTime,
recipients: [], recipients: []
fromDate
}), }),
[repeatDays, message, nextReminderDate, fromDate] [repeatDays, message, nextReminderDate]
); );
return { return {
@@ -161,8 +153,7 @@ export const CreateReminderForm = ({
message: reminderData?.message || "", message: reminderData?.message || "",
nextReminderDate: reminderData?.nextReminderDate || null, nextReminderDate: reminderData?.nextReminderDate || null,
reminderType: reminderData?.repeatDays ? ReminderType.Recurring : ReminderType.OneTime, reminderType: reminderData?.repeatDays ? ReminderType.Recurring : ReminderType.OneTime,
recipients: [], recipients: []
fromDate: reminderData?.fromDate
}, },
resolver: zodResolver(ReminderFormSchema) resolver: zodResolver(ReminderFormSchema)
}); });
@@ -179,7 +170,6 @@ export const CreateReminderForm = ({
// Watch form values // Watch form values
const reminderType = watch("reminderType"); const reminderType = watch("reminderType");
const fromDate = watch("fromDate");
// Invalidate queries helper // Invalidate queries helper
const invalidateQueries = () => { const invalidateQueries = () => {
@@ -205,8 +195,7 @@ export const CreateReminderForm = ({
message: data.message, message: data.message,
recipients: data.recipients?.map((r) => r.value) || [], recipients: data.recipients?.map((r) => r.value) || [],
secretId, secretId,
nextReminderDate: data.nextReminderDate, nextReminderDate: data.nextReminderDate
fromDate: data.fromDate
}); });
invalidateQueries(); invalidateQueries();
@@ -254,7 +243,6 @@ export const CreateReminderForm = ({
if (newType === ReminderType.Recurring) { if (newType === ReminderType.Recurring) {
setValue("repeatDays", DEFAULT_REPEAT_DAYS); setValue("repeatDays", DEFAULT_REPEAT_DAYS);
setValue("nextReminderDate", null); setValue("nextReminderDate", null);
setValue("fromDate", null);
} else if (newType === ReminderType.OneTime) { } else if (newType === ReminderType.OneTime) {
const tomorrow = new Date(); const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1); tomorrow.setDate(tomorrow.getDate() + 1);
@@ -271,7 +259,6 @@ export const CreateReminderForm = ({
const { const {
repeatDays: repeatDaysInitial, repeatDays: repeatDaysInitial,
fromDate: fromDateInitial,
message, message,
recipients, recipients,
nextReminderDate: nextReminderDateInitial nextReminderDate: nextReminderDateInitial
@@ -279,7 +266,6 @@ export const CreateReminderForm = ({
if (repeatDaysInitial) { if (repeatDaysInitial) {
setValue("repeatDays", repeatDaysInitial); setValue("repeatDays", repeatDaysInitial);
setValue("fromDate", fromDateInitial);
setValue("reminderType", ReminderType.Recurring); setValue("reminderType", ReminderType.Recurring);
} else { } else {
setValue("reminderType", ReminderType.OneTime); setValue("reminderType", ReminderType.OneTime);
@@ -337,7 +323,6 @@ export const CreateReminderForm = ({
{/* Conditional Fields Based on Reminder Type */} {/* Conditional Fields Based on Reminder Type */}
{reminderType === ReminderType.Recurring ? ( {reminderType === ReminderType.Recurring ? (
<div className="grid grid-cols-[1fr,auto] gap-x-2">
<Controller <Controller
control={control} control={control}
name="repeatDays" name="repeatDays"
@@ -362,6 +347,7 @@ export const CreateReminderForm = ({
max={MAX_REPEAT_DAYS} max={MAX_REPEAT_DAYS}
/> />
</FormControl> </FormControl>
{/* Interval description */} {/* Interval description */}
<div <div
className={twMerge( className={twMerge(
@@ -371,39 +357,10 @@ export const CreateReminderForm = ({
> >
A reminder will be sent every{" "} A reminder will be sent every{" "}
{field.value && field.value > 1 ? `${field.value} days` : "day"} {field.value && field.value > 1 ? `${field.value} days` : "day"}
{fromDate ? ` starting from ${format(fromDate, "MM/dd/yy")}` : ""}
</div> </div>
</div> </div>
)} )}
/> />
<Controller
control={control}
name="fromDate"
render={({ field, fieldState }) => (
<FormControl
className="mb-0"
label="Start Date"
tooltipText="When enabled, this date will be used as the start date for the first reminder"
isError={Boolean(fieldState.error)}
errorText={fieldState.error?.message || ""}
>
<DatePicker
value={field.value || undefined}
className="w-full"
onChange={field.onChange}
dateFormat="P"
popUpProps={{
open: isDatePickerOpen,
onOpenChange: setIsDatePickerOpen
}}
popUpContentProps={{}}
hideTime
hidden={{ before: new Date(Date.now() + ONE_DAY_IN_MILLIS) }}
/>
</FormControl>
)}
/>
</div>
) : ( ) : (
<Controller <Controller
control={control} control={control}
@@ -428,7 +385,7 @@ export const CreateReminderForm = ({
}} }}
popUpContentProps={{}} popUpContentProps={{}}
hideTime hideTime
hidden={{ before: new Date(Date.now() + ONE_DAY_IN_MILLIS) }} hidden={{ before: new Date(Date.now() + 86400000) }}
/> />
</FormControl> </FormControl>
</div> </div>

View File

@@ -13,6 +13,8 @@ type GenericInfisicalAuthentication struct {
GcpIdTokenAuth GenericGcpIdTokenAuth `json:"gcpIdTokenAuth,omitempty"` GcpIdTokenAuth GenericGcpIdTokenAuth `json:"gcpIdTokenAuth,omitempty"`
// +kubebuilder:validation:Optional // +kubebuilder:validation:Optional
GcpIamAuth GenericGcpIamAuth `json:"gcpIamAuth,omitempty"` GcpIamAuth GenericGcpIamAuth `json:"gcpIamAuth,omitempty"`
// +kubebuilder:validation:Optional
LdapAuth GenericLdapAuth `json:"ldapAuth,omitempty"`
} }
type GenericUniversalAuth struct { type GenericUniversalAuth struct {
@@ -20,6 +22,13 @@ type GenericUniversalAuth struct {
CredentialsRef KubeSecretReference `json:"credentialsRef"` CredentialsRef KubeSecretReference `json:"credentialsRef"`
} }
type GenericLdapAuth struct {
// +kubebuilder:validation:Required
IdentityID string `json:"identityId"`
// +kubebuilder:validation:Required
CredentialsRef KubeSecretReference `json:"credentialsRef"`
}
type GenericAwsIamAuth struct { type GenericAwsIamAuth struct {
// +kubebuilder:validation:Required // +kubebuilder:validation:Required
IdentityID string `json:"identityId"` IdentityID string `json:"identityId"`

View File

@@ -21,6 +21,8 @@ type Authentication struct {
GcpIdTokenAuth GCPIdTokenAuthDetails `json:"gcpIdTokenAuth"` GcpIdTokenAuth GCPIdTokenAuthDetails `json:"gcpIdTokenAuth"`
// +kubebuilder:validation:Optional // +kubebuilder:validation:Optional
GcpIamAuth GcpIamAuthDetails `json:"gcpIamAuth"` GcpIamAuth GcpIamAuthDetails `json:"gcpIamAuth"`
// +kubebuilder:validation:Optional
LdapAuth LdapAuthDetails `json:"ldapAuth"`
} }
type UniversalAuthDetails struct { type UniversalAuthDetails struct {
@@ -30,6 +32,15 @@ type UniversalAuthDetails struct {
SecretsScope MachineIdentityScopeInWorkspace `json:"secretsScope"` SecretsScope MachineIdentityScopeInWorkspace `json:"secretsScope"`
} }
type LdapAuthDetails struct {
// +kubebuilder:validation:Required
IdentityID string `json:"identityId"`
// +kubebuilder:validation:Required
CredentialsRef KubeSecretReference `json:"credentialsRef"`
// +kubebuilder:validation:Required
SecretsScope MachineIdentityScopeInWorkspace `json:"secretsScope"`
}
type KubernetesAuthDetails struct { type KubernetesAuthDetails struct {
// +kubebuilder:validation:Required // +kubebuilder:validation:Required
IdentityID string `json:"identityId"` IdentityID string `json:"identityId"`

View File

@@ -53,6 +53,7 @@ func (in *Authentication) DeepCopyInto(out *Authentication) {
out.AzureAuth = in.AzureAuth out.AzureAuth = in.AzureAuth
out.GcpIdTokenAuth = in.GcpIdTokenAuth out.GcpIdTokenAuth = in.GcpIdTokenAuth
out.GcpIamAuth = in.GcpIamAuth out.GcpIamAuth = in.GcpIamAuth
out.LdapAuth = in.LdapAuth
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Authentication. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Authentication.
@@ -326,6 +327,7 @@ func (in *GenericInfisicalAuthentication) DeepCopyInto(out *GenericInfisicalAuth
out.AzureAuth = in.AzureAuth out.AzureAuth = in.AzureAuth
out.GcpIdTokenAuth = in.GcpIdTokenAuth out.GcpIdTokenAuth = in.GcpIdTokenAuth
out.GcpIamAuth = in.GcpIamAuth out.GcpIamAuth = in.GcpIamAuth
out.LdapAuth = in.LdapAuth
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericInfisicalAuthentication. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericInfisicalAuthentication.
@@ -359,6 +361,22 @@ func (in *GenericKubernetesAuth) DeepCopy() *GenericKubernetesAuth {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GenericLdapAuth) DeepCopyInto(out *GenericLdapAuth) {
*out = *in
out.CredentialsRef = in.CredentialsRef
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericLdapAuth.
func (in *GenericLdapAuth) DeepCopy() *GenericLdapAuth {
if in == nil {
return nil
}
out := new(GenericLdapAuth)
in.DeepCopyInto(out)
return out
}
// 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 *GenericUniversalAuth) DeepCopyInto(out *GenericUniversalAuth) { func (in *GenericUniversalAuth) DeepCopyInto(out *GenericUniversalAuth) {
*out = *in *out = *in
@@ -810,6 +828,23 @@ func (in *KubernetesServiceAccountRef) DeepCopy() *KubernetesServiceAccountRef {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LdapAuthDetails) DeepCopyInto(out *LdapAuthDetails) {
*out = *in
out.CredentialsRef = in.CredentialsRef
out.SecretsScope = in.SecretsScope
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LdapAuthDetails.
func (in *LdapAuthDetails) DeepCopy() *LdapAuthDetails {
if in == nil {
return nil
}
out := new(LdapAuthDetails)
in.DeepCopyInto(out)
return out
}
// 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 *MachineIdentityScopeInWorkspace) DeepCopyInto(out *MachineIdentityScopeInWorkspace) { func (in *MachineIdentityScopeInWorkspace) DeepCopyInto(out *MachineIdentityScopeInWorkspace) {
*out = *in *out = *in

View File

@@ -103,6 +103,27 @@ spec:
- identityId - identityId
- serviceAccountRef - serviceAccountRef
type: object type: object
ldapAuth:
properties:
credentialsRef:
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
identityId:
type: string
required:
- credentialsRef
- identityId
type: object
universalAuth: universalAuth:
properties: properties:
credentialsRef: credentialsRef:

View File

@@ -103,6 +103,27 @@ spec:
- identityId - identityId
- serviceAccountRef - serviceAccountRef
type: object type: object
ldapAuth:
properties:
credentialsRef:
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
identityId:
type: string
required:
- credentialsRef
- identityId
type: object
universalAuth: universalAuth:
properties: properties:
credentialsRef: credentialsRef:

View File

@@ -181,6 +181,43 @@ spec:
- secretsScope - secretsScope
- serviceAccountRef - serviceAccountRef
type: object type: object
ldapAuth:
properties:
credentialsRef:
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
identityId:
type: string
secretsScope:
properties:
envSlug:
type: string
projectSlug:
type: string
recursive:
type: boolean
secretsPath:
type: string
required:
- envSlug
- projectSlug
- secretsPath
type: object
required:
- credentialsRef
- identityId
- secretsScope
type: object
serviceAccount: serviceAccount:
properties: properties:
environmentName: environmentName:

View File

@@ -65,6 +65,19 @@ spec:
secretsPath: "/path" secretsPath: "/path"
recursive: true recursive: true
ldapAuth:
identityId: <machine-identity-id>
credentialsRef:
secretName: <secret-name> # ldap-auth-credentials
secretNamespace: <secret-namespace> # default
# secretsScope is identical to the secrets scope in the universalAuth field in this sample.
secretsScope:
projectSlug: your-project-slug
envSlug: prod
secretsPath: "/path"
recursive: true
# Azure Auth # Azure Auth
azureAuth: azureAuth:
identityId: <your-machine-identity-id> identityId: <your-machine-identity-id>

View File

@@ -0,0 +1,8 @@
apiVersion: v1
kind: Secret
metadata:
name: ldap-auth-credentials
type: Opaque
stringData:
username: <ldap-username>
password: <ldap-password>

View File

@@ -85,6 +85,7 @@ func (r *InfisicalDynamicSecretReconciler) handleAuthentication(ctx context.Cont
util.AuthStrategy.AZURE_MACHINE_IDENTITY: util.HandleAzureAuth, util.AuthStrategy.AZURE_MACHINE_IDENTITY: util.HandleAzureAuth,
util.AuthStrategy.GCP_ID_TOKEN_MACHINE_IDENTITY: util.HandleGcpIdTokenAuth, util.AuthStrategy.GCP_ID_TOKEN_MACHINE_IDENTITY: util.HandleGcpIdTokenAuth,
util.AuthStrategy.GCP_IAM_MACHINE_IDENTITY: util.HandleGcpIamAuth, util.AuthStrategy.GCP_IAM_MACHINE_IDENTITY: util.HandleGcpIamAuth,
util.AuthStrategy.LDAP_MACHINE_IDENTITY: util.HandleLdapAuth,
} }
for authStrategy, authHandler := range authStrategies { for authStrategy, authHandler := range authStrategies {

View File

@@ -32,6 +32,7 @@ func (r *InfisicalPushSecretReconciler) handleAuthentication(ctx context.Context
util.AuthStrategy.AZURE_MACHINE_IDENTITY: util.HandleAzureAuth, util.AuthStrategy.AZURE_MACHINE_IDENTITY: util.HandleAzureAuth,
util.AuthStrategy.GCP_ID_TOKEN_MACHINE_IDENTITY: util.HandleGcpIdTokenAuth, util.AuthStrategy.GCP_ID_TOKEN_MACHINE_IDENTITY: util.HandleGcpIdTokenAuth,
util.AuthStrategy.GCP_IAM_MACHINE_IDENTITY: util.HandleGcpIamAuth, util.AuthStrategy.GCP_IAM_MACHINE_IDENTITY: util.HandleGcpIamAuth,
util.AuthStrategy.LDAP_MACHINE_IDENTITY: util.HandleLdapAuth,
} }
for authStrategy, authHandler := range authStrategies { for authStrategy, authHandler := range authStrategies {

View File

@@ -57,6 +57,7 @@ func (r *InfisicalSecretReconciler) handleAuthentication(ctx context.Context, in
util.AuthStrategy.AZURE_MACHINE_IDENTITY: util.HandleAzureAuth, util.AuthStrategy.AZURE_MACHINE_IDENTITY: util.HandleAzureAuth,
util.AuthStrategy.GCP_ID_TOKEN_MACHINE_IDENTITY: util.HandleGcpIdTokenAuth, util.AuthStrategy.GCP_ID_TOKEN_MACHINE_IDENTITY: util.HandleGcpIdTokenAuth,
util.AuthStrategy.GCP_IAM_MACHINE_IDENTITY: util.HandleGcpIamAuth, util.AuthStrategy.GCP_IAM_MACHINE_IDENTITY: util.HandleGcpIamAuth,
util.AuthStrategy.LDAP_MACHINE_IDENTITY: util.HandleLdapAuth,
} }
for authStrategy, authHandler := range authStrategies { for authStrategy, authHandler := range authStrategies {

View File

@@ -5,7 +5,7 @@ go 1.21
require ( require (
github.com/Masterminds/sprig/v3 v3.3.0 github.com/Masterminds/sprig/v3 v3.3.0
github.com/aws/smithy-go v1.20.3 github.com/aws/smithy-go v1.20.3
github.com/infisical/go-sdk v0.5.97 github.com/infisical/go-sdk v0.5.99
github.com/lestrrat-go/jwx/v2 v2.1.4 github.com/lestrrat-go/jwx/v2 v2.1.4
github.com/onsi/ginkgo/v2 v2.6.0 github.com/onsi/ginkgo/v2 v2.6.0
github.com/onsi/gomega v1.24.1 github.com/onsi/gomega v1.24.1
@@ -40,6 +40,7 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/goccy/go-json v0.10.3 // indirect github.com/goccy/go-json v0.10.3 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/google/s2a-go v0.1.7 // indirect github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.5 // indirect github.com/googleapis/gax-go/v2 v2.12.5 // indirect
@@ -52,9 +53,12 @@ require (
github.com/lestrrat-go/option v1.0.1 // indirect github.com/lestrrat-go/option v1.0.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/oracle/oci-go-sdk/v65 v65.95.2 // indirect
github.com/segmentio/asm v1.2.0 // indirect github.com/segmentio/asm v1.2.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cast v1.7.0 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect

View File

@@ -152,6 +152,8 @@ github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -237,6 +239,8 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/infisical/go-sdk v0.5.97 h1:veOi6Hduda6emtwjdUI5SBg2qd2iDQc5xLKqZ15KSoM= github.com/infisical/go-sdk v0.5.97 h1:veOi6Hduda6emtwjdUI5SBg2qd2iDQc5xLKqZ15KSoM=
github.com/infisical/go-sdk v0.5.97/go.mod h1:ExjqFLRz7LSpZpGluqDLvFl6dFBLq5LKyLW7GBaMAIs= github.com/infisical/go-sdk v0.5.97/go.mod h1:ExjqFLRz7LSpZpGluqDLvFl6dFBLq5LKyLW7GBaMAIs=
github.com/infisical/go-sdk v0.5.99 h1:trvn7JhKYuSzDkc44h+yqToVjclkrRyP42t315k5kEE=
github.com/infisical/go-sdk v0.5.99/go.mod h1:j2D2a5WPNdKXDfHO+3y/TNyLWh5Aq9QYS7EcGI96LZI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
@@ -303,6 +307,8 @@ github.com/onsi/ginkgo/v2 v2.6.0 h1:9t9b9vRUbFq3C4qKFCGkVuq/fIHji802N1nrtkh1mNc=
github.com/onsi/ginkgo/v2 v2.6.0/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc= github.com/onsi/ginkgo/v2 v2.6.0/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
github.com/oracle/oci-go-sdk/v65 v65.95.2 h1:0HJ0AgpLydp/DtvYrF2d4str2BjXOVAeNbuW7E07g94=
github.com/oracle/oci-go-sdk/v65 v65.95.2/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -347,6 +353,8 @@ github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+D
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -365,8 +373,11 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -407,6 +418,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
@@ -551,6 +563,7 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
@@ -559,6 +572,7 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=

View File

@@ -6,11 +6,16 @@ type ServiceAccountDetails struct {
PrivateKey string PrivateKey string
} }
type MachineIdentityDetails struct { type UniversalAuthIdentityDetails struct {
ClientId string ClientId string
ClientSecret string ClientSecret string
} }
type LdapIdentityDetails struct {
Username string
Password string
}
type SingleEnvironmentVariable struct { type SingleEnvironmentVariable struct {
Key string `json:"key"` Key string `json:"key"`
Value string `json:"value"` Value string `json:"value"`

View File

@@ -88,6 +88,7 @@ var AuthStrategy = struct {
AZURE_MACHINE_IDENTITY AuthStrategyType AZURE_MACHINE_IDENTITY AuthStrategyType
GCP_ID_TOKEN_MACHINE_IDENTITY AuthStrategyType GCP_ID_TOKEN_MACHINE_IDENTITY AuthStrategyType
GCP_IAM_MACHINE_IDENTITY AuthStrategyType GCP_IAM_MACHINE_IDENTITY AuthStrategyType
LDAP_MACHINE_IDENTITY AuthStrategyType
}{ }{
SERVICE_TOKEN: "SERVICE_TOKEN", SERVICE_TOKEN: "SERVICE_TOKEN",
SERVICE_ACCOUNT: "SERVICE_ACCOUNT", SERVICE_ACCOUNT: "SERVICE_ACCOUNT",
@@ -97,6 +98,7 @@ var AuthStrategy = struct {
AZURE_MACHINE_IDENTITY: "AZURE_MACHINE_IDENTITY", AZURE_MACHINE_IDENTITY: "AZURE_MACHINE_IDENTITY",
GCP_ID_TOKEN_MACHINE_IDENTITY: "GCP_ID_TOKEN_MACHINE_IDENTITY", GCP_ID_TOKEN_MACHINE_IDENTITY: "GCP_ID_TOKEN_MACHINE_IDENTITY",
GCP_IAM_MACHINE_IDENTITY: "GCP_IAM_MACHINE_IDENTITY", GCP_IAM_MACHINE_IDENTITY: "GCP_IAM_MACHINE_IDENTITY",
LDAP_MACHINE_IDENTITY: "LDAP_MACHINE_IDENTITY",
} }
type SecretCrdType string type SecretCrdType string
@@ -188,6 +190,71 @@ func HandleUniversalAuth(ctx context.Context, reconcilerClient client.Client, se
}, nil }, nil
} }
func HandleLdapAuth(ctx context.Context, reconcilerClient client.Client, secretCrd SecretAuthInput, infisicalClient infisicalSdk.InfisicalClientInterface) (AuthenticationDetails, error) {
var ldapAuthSpec v1alpha1.LdapAuthDetails
switch secretCrd.Type {
case SecretCrd.INFISICAL_SECRET:
infisicalSecret, ok := secretCrd.Secret.(v1alpha1.InfisicalSecret)
if !ok {
return AuthenticationDetails{}, errors.New("unable to cast secret to InfisicalSecret")
}
ldapAuthSpec = infisicalSecret.Spec.Authentication.LdapAuth
case SecretCrd.INFISICAL_PUSH_SECRET:
infisicalPushSecret, ok := secretCrd.Secret.(v1alpha1.InfisicalPushSecret)
if !ok {
return AuthenticationDetails{}, errors.New("unable to cast secret to InfisicalPushSecret")
}
ldapAuthSpec = v1alpha1.LdapAuthDetails{
CredentialsRef: infisicalPushSecret.Spec.Authentication.LdapAuth.CredentialsRef,
SecretsScope: v1alpha1.MachineIdentityScopeInWorkspace{},
IdentityID: infisicalPushSecret.Spec.Authentication.LdapAuth.IdentityID,
}
case SecretCrd.INFISICAL_DYNAMIC_SECRET:
infisicalDynamicSecret, ok := secretCrd.Secret.(v1alpha1.InfisicalDynamicSecret)
if !ok {
return AuthenticationDetails{}, errors.New("unable to cast secret to InfisicalDynamicSecret")
}
ldapAuthSpec = v1alpha1.LdapAuthDetails{
CredentialsRef: infisicalDynamicSecret.Spec.Authentication.LdapAuth.CredentialsRef,
SecretsScope: v1alpha1.MachineIdentityScopeInWorkspace{},
IdentityID: infisicalDynamicSecret.Spec.Authentication.LdapAuth.IdentityID,
}
}
ldapAuthKubeSecret, err := GetInfisicalLdapAuthFromKubeSecret(ctx, reconcilerClient, v1alpha1.KubeSecretReference{
SecretNamespace: ldapAuthSpec.CredentialsRef.SecretNamespace,
SecretName: ldapAuthSpec.CredentialsRef.SecretName,
})
if err != nil {
return AuthenticationDetails{}, fmt.Errorf("ReconcileInfisicalSecret: unable to get machine identity creds from kube secret [err=%s]", err)
}
if ldapAuthKubeSecret.Username == "" && ldapAuthKubeSecret.Password == "" {
return AuthenticationDetails{}, ErrAuthNotApplicable
}
_, err = infisicalClient.Auth().LdapAuthLogin(ldapAuthSpec.IdentityID, ldapAuthKubeSecret.Username, ldapAuthKubeSecret.Password)
if err != nil {
return AuthenticationDetails{}, fmt.Errorf("unable to login with machine identity credentials [err=%s]", err)
}
return AuthenticationDetails{
AuthStrategy: AuthStrategy.LDAP_MACHINE_IDENTITY,
MachineIdentityScope: ldapAuthSpec.SecretsScope,
IsMachineIdentityAuth: true,
SecretType: secretCrd.Type,
}, nil
}
func HandleKubernetesAuth(ctx context.Context, reconcilerClient client.Client, secretCrd SecretAuthInput, infisicalClient infisicalSdk.InfisicalClientInterface) (AuthenticationDetails, error) { func HandleKubernetesAuth(ctx context.Context, reconcilerClient client.Client, secretCrd SecretAuthInput, infisicalClient infisicalSdk.InfisicalClientInterface) (AuthenticationDetails, error) {
var kubernetesAuthSpec v1alpha1.KubernetesAuthDetails var kubernetesAuthSpec v1alpha1.KubernetesAuthDetails

View File

@@ -18,6 +18,9 @@ import (
const INFISICAL_MACHINE_IDENTITY_CLIENT_ID = "clientId" const INFISICAL_MACHINE_IDENTITY_CLIENT_ID = "clientId"
const INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET = "clientSecret" const INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET = "clientSecret"
const INFISICAL_MACHINE_IDENTITY_LDAP_USERNAME = "username"
const INFISICAL_MACHINE_IDENTITY_LDAP_PASSWORD = "password"
func GetKubeSecretByNamespacedName(ctx context.Context, reconcilerClient client.Client, namespacedName types.NamespacedName) (*corev1.Secret, error) { func GetKubeSecretByNamespacedName(ctx context.Context, reconcilerClient client.Client, namespacedName types.NamespacedName) (*corev1.Secret, error) {
kubeSecret := &corev1.Secret{} kubeSecret := &corev1.Secret{}
err := reconcilerClient.Get(ctx, namespacedName, kubeSecret) err := reconcilerClient.Get(ctx, namespacedName, kubeSecret)
@@ -38,7 +41,7 @@ func GetKubeConfigMapByNamespacedName(ctx context.Context, reconcilerClient clie
return kubeConfigMap, err return kubeConfigMap, err
} }
func GetInfisicalUniversalAuthFromKubeSecret(ctx context.Context, reconcilerClient client.Client, universalAuthRef v1alpha1.KubeSecretReference) (machineIdentityDetails model.MachineIdentityDetails, err error) { func GetInfisicalUniversalAuthFromKubeSecret(ctx context.Context, reconcilerClient client.Client, universalAuthRef v1alpha1.KubeSecretReference) (machineIdentityDetails model.UniversalAuthIdentityDetails, err error) {
universalAuthCredsFromKubeSecret, err := GetKubeSecretByNamespacedName(ctx, reconcilerClient, types.NamespacedName{ universalAuthCredsFromKubeSecret, err := GetKubeSecretByNamespacedName(ctx, reconcilerClient, types.NamespacedName{
Namespace: universalAuthRef.SecretNamespace, Namespace: universalAuthRef.SecretNamespace,
@@ -48,17 +51,39 @@ func GetInfisicalUniversalAuthFromKubeSecret(ctx context.Context, reconcilerClie
}) })
if k8Errors.IsNotFound(err) { if k8Errors.IsNotFound(err) {
return model.MachineIdentityDetails{}, nil return model.UniversalAuthIdentityDetails{}, nil
} }
if err != nil { if err != nil {
return model.MachineIdentityDetails{}, fmt.Errorf("something went wrong when fetching your machine identity credentials [err=%s]", err) return model.UniversalAuthIdentityDetails{}, fmt.Errorf("something went wrong when fetching your machine identity credentials [err=%s]", err)
} }
clientIdFromSecret := universalAuthCredsFromKubeSecret.Data[INFISICAL_MACHINE_IDENTITY_CLIENT_ID] clientIdFromSecret := universalAuthCredsFromKubeSecret.Data[INFISICAL_MACHINE_IDENTITY_CLIENT_ID]
clientSecretFromSecret := universalAuthCredsFromKubeSecret.Data[INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET] clientSecretFromSecret := universalAuthCredsFromKubeSecret.Data[INFISICAL_MACHINE_IDENTITY_CLIENT_SECRET]
return model.MachineIdentityDetails{ClientId: string(clientIdFromSecret), ClientSecret: string(clientSecretFromSecret)}, nil return model.UniversalAuthIdentityDetails{ClientId: string(clientIdFromSecret), ClientSecret: string(clientSecretFromSecret)}, nil
}
func GetInfisicalLdapAuthFromKubeSecret(ctx context.Context, reconcilerClient client.Client, ldapAuthRef v1alpha1.KubeSecretReference) (machineIdentityDetails model.LdapIdentityDetails, err error) {
ldapAuthCredsFromKubeSecret, err := GetKubeSecretByNamespacedName(ctx, reconcilerClient, types.NamespacedName{
Namespace: ldapAuthRef.SecretNamespace,
Name: ldapAuthRef.SecretName,
})
if k8Errors.IsNotFound(err) {
return model.LdapIdentityDetails{}, nil
}
if err != nil {
return model.LdapIdentityDetails{}, fmt.Errorf("something went wrong when fetching your machine identity credentials [err=%s]", err)
}
usernameFromSecret := ldapAuthCredsFromKubeSecret.Data[INFISICAL_MACHINE_IDENTITY_LDAP_USERNAME]
passwordFromSecret := ldapAuthCredsFromKubeSecret.Data[INFISICAL_MACHINE_IDENTITY_LDAP_PASSWORD]
return model.LdapIdentityDetails{Username: string(usernameFromSecret), Password: string(passwordFromSecret)}, nil
} }