Skip to content
Merged
71 changes: 58 additions & 13 deletions src/iac/lib/stacks/cloudfront-url-rewrite.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
// CloudFront Function for URL rewriting
// Compatible with CloudFront Functions runtime (ES5.1)
// Query strings are automatically preserved by CloudFront

function handler(event) {
var req = event.request;
var uri = req.uri;
Expand Down Expand Up @@ -48,22 +44,71 @@ function handler(event) {
return false;
}

function getQueryString(querystring) {
if (typeof querystring === "string") {
return querystring ? "?" + querystring : "";
}

var parts = [];
for (var key in querystring) {
if (Object.prototype.hasOwnProperty.call(querystring, key)) {
var parameter = querystring[key];
if (parameter == null || typeof parameter !== "object") {
continue;
}
var values = Array.isArray(parameter.multiValue)
? parameter.multiValue
: [parameter];

for (var i = 0; i < values.length; i++) {
var entry = values[i];
if (entry == null || typeof entry !== "object") {
continue;
}
var hasValue = Object.prototype.hasOwnProperty.call(
entry,
"value",
);
parts.push(
encodeURIComponent(key) +
(hasValue ? "=" + encodeURIComponent(entry.value) : ""),
);
}
}
}

return parts.length ? "?" + parts.join("&") : "";
}

function redirect(path) {
return {
statusCode: 301,
statusDescription: "Moved Permanently",
headers: {
location: {
value: path + getQueryString(req.querystring),
},
},
};
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if (uri === "/sitemap.xml") {
return redirect("/sitemap-index.xml");
}

// Exclude API routes
var lower = uri.toLowerCase();
if (hasPrefix(lower, "/api/")) {
return req; // no changes
}

// Remove trailing slash (except homepage)
if (uri !== "/" && endsWith(uri, "/")) {
uri = uri.substring(0, uri.length - 1);
lower = uri.toLowerCase(); // recompute after modifying uri
}

// Append /index.html if not homepage and no known extension
// Astro generates directory-based URLs: /docs → /docs/index.html
// Astro generates directory-based URLs with trailing slashes.
if (uri !== "/" && !hasKnownExt(lower)) {
uri += "/index.html";
if (!endsWith(uri, "/")) {
return redirect(uri + "/");
}

uri += "index.html";
}

req.uri = uri;
Expand Down
8 changes: 4 additions & 4 deletions src/iac/lib/stacks/staticWebsiteStack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,15 @@ export class StaticWebsiteStack extends CustomStack {

const errorResponse403: ErrorResponse = {
httpStatus: 403,
responseHttpStatus: 200,
responsePagePath: "/index.html",
responseHttpStatus: 404,
responsePagePath: "/404.html",
ttl: Duration.seconds(10),
};

const errorResponse404: ErrorResponse = {
httpStatus: 404,
responseHttpStatus: 200,
responsePagePath: "/index.html",
responseHttpStatus: 404,
responsePagePath: "/404.html",
ttl: Duration.seconds(10),
};

Expand Down
70 changes: 70 additions & 0 deletions src/website/public/llms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Envilder

> Envilder is MIT-licensed, open-source mapping and secret-resolution tooling for AWS SSM Parameter Store and Azure Key Vault. One `envilder.json` mapping contract is used across local development, CI/CD, and application startup.

- Scope: Envilder is a mapping and resolution layer, not a secret manager, hosted SaaS, proxy, or control plane. The cloud provider remains the source of truth; Envilder has no hosted secret store or proxy.
- CLI: pulls mapped values to `.env` and supports intentional controlled push.
- GitHub Action: pulls mapped values to `.env` in CI/CD.
- Runtime SDKs: .NET, Python, and Node.js resolve values in-process and can return them or inject process environment variables. The .NET SDK also integrates with configuration and dependency injection APIs.
- Best fit: small teams, projects, or straightforward applications already using SSM or Key Vault that want a version-controlled, PR-reviewable mapping without a separate hosted service. Container and Kubernetes workloads can use runtime SDKs with provider-native identity, but this is application-side resolution, not a native Kubernetes Secret sync, operator, or controller.
- It is not the primary fit when the required backend is unsupported, a hosted or full secret-management control plane is needed, or native Kubernetes secret synchronization is required.
- Google Cloud Secret Manager and AWS Secrets Manager are roadmap items; neither is shipped or scheduled. Request unsupported providers or integrations through the [GitHub issue form](https://github.com/macalbert/envilder/issues/new); requests help prioritize work but do not guarantee implementation.
- Typical CLI flow: configure cloud credentials, keep secret values in the supported cloud store, commit only names and paths in `envilder.json`, then run `npx envilder --map=envilder.json --envfile=.env`. Use the GitHub Action for CI/CD or a runtime SDK for in-process resolution.

Minimal AWS SSM map:

```json
{
"$schema": "https://envilder.com/schema/map-file.v1.json",
"DB_PASSWORD": "/my-app/prod/db-password"
}
```

## Start here

- [Product overview](https://envilder.com/): Envilder's website and product introduction.
- [Website documentation](https://envilder.com/docs/): Documentation hub.
- [Source repository](https://github.com/macalbert/envilder): Project source, issues, releases, and contribution history.
- [Canonical README](https://raw.githubusercontent.com/macalbert/envilder/main/README.md): Primary repository overview in Markdown.
- [Map-file JSON Schema](https://envilder.com/schema/map-file.v1.json): Schema for `envilder.json`.

## CLI and CI/CD

- [Installation requirements](https://raw.githubusercontent.com/macalbert/envilder/main/docs/requirements-installation.md): CLI prerequisites and installation guidance.
- [Pull command guide](https://raw.githubusercontent.com/macalbert/envilder/main/docs/pull-command.md): Resolve mapped values into a `.env` file.
- [Push command guide](https://raw.githubusercontent.com/macalbert/envilder/main/docs/push-command.md): Intentional controlled CLI push workflows.
- [GitHub Action documentation](https://raw.githubusercontent.com/macalbert/envilder/main/github-action/README.md): Pull-only CI/CD action usage.

## Runtime SDKs

- [.NET SDK documentation](https://raw.githubusercontent.com/macalbert/envilder/main/src/sdks/dotnet/README.md): Runtime resolution for .NET applications.
- [Python SDK documentation](https://raw.githubusercontent.com/macalbert/envilder/main/src/sdks/python/README.md): Runtime resolution for Python applications.
- [Node.js SDK documentation](https://raw.githubusercontent.com/macalbert/envilder/main/src/sdks/nodejs/README.md): Runtime resolution for Node.js applications.

## Published packages

- [CLI on npm](https://www.npmjs.com/package/envilder): Install the CLI package `envilder`.
- [.NET SDK on NuGet](https://www.nuget.org/packages/Envilder/): Install the .NET runtime SDK package `Envilder`.
- [Python SDK on PyPI](https://pypi.org/project/envilder/): Install the Python runtime SDK package `envilder`.
- [Node.js SDK on npm](https://www.npmjs.com/package/@envilder/sdk): Install the Node.js runtime SDK package `@envilder/sdk`.

## Examples

- [Examples README](https://raw.githubusercontent.com/macalbert/envilder-examples/main/README.md): Reproducible .NET, Python, and TypeScript examples using Testcontainers and LocalStack, plus .NET and TypeScript Aspire examples; paths, not values, are committed.
- [Examples repository](https://github.com/macalbert/envilder-examples): Source for the supported example scope above.

## Project status and contribution

- [Roadmap](https://raw.githubusercontent.com/macalbert/envilder/main/ROADMAP.md): Planned and in-progress work; roadmap items are not release commitments.
- [Changelog](https://envilder.com/changelog/): Released changes.
- [MIT license](https://raw.githubusercontent.com/macalbert/envilder/main/LICENSE): Terms for using, modifying, and distributing Envilder.
- [Security policy](https://raw.githubusercontent.com/macalbert/envilder/main/docs/SECURITY.md): Vulnerability reporting guidance.
- [Contributing guide](https://raw.githubusercontent.com/macalbert/envilder/main/CONTRIBUTING.md): Contribution process and local development guidance.
- [Feature request or issue](https://github.com/macalbert/envilder/issues/new): Request an unsupported provider or integration, or report a problem.

## Optional

- [LocalStack token hygiene](https://dev.to/macalbert/how-i-run-localstack-without-committing-localstackauthtoken-34gk): Maintainer-authored supplementary article on keeping `LOCALSTACK_AUTH_TOKEN` out of commits.
- [LocalStack integration tests without env files](https://dev.to/macalbert/localstack-integration-tests-without-env-files-b75): Maintainer-authored supplementary article.
- [One year of Envilder](https://dev.to/macalbert/one-year-of-envilder-from-a-cli-script-to-sdks-push-mode-and-a-website-h49): Maintainer-authored supplementary retrospective.
- [Original AWS SSM CLI workflow](https://dev.to/macalbert/stop-hardcoding-secrets-generate-env-files-from-aws-ssm-with-a-simple-cli-f77): Maintainer-authored supplementary historical context documenting the original AWS SSM CLI workflow.
4 changes: 4 additions & 0 deletions src/website/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
User-agent: *
Allow: /

Sitemap: https://envilder.com/sitemap-index.xml
19 changes: 15 additions & 4 deletions src/website/src/i18n/ca.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ import type { Translations } from './types';
export const ca: Translations = {
homeMeta: {
title:
'Envilder: estandarditza com les teves aplicacions consumeixen secrets a cada entorn i runtime.',
'Gestió de secrets open source per a AWS SSM i Azure Key Vault | Envilder',
description:
"Defineix el contracte d'entorn una vegada i resol-lo de forma consistent en desenvolupament local, CI/CD i runtime. Amb AWS SSM Parameter Store i Azure Key Vault.",
"Envilder és una CLI, GitHub Action i SDK de runtime open source per carregar secrets des d'AWS SSM Parameter Store i Azure Key Vault.",
},
notFound: {
title: 'Pàgina no trobada | Envilder',
description: "La pàgina d'Envilder sol·licitada no existeix.",
heading: 'No hem trobat aquesta pàgina',
body: "L'adreça pot ser incorrecta o la pàgina pot haver-se mogut.",
home: 'Torna a l’inici',
},
nav: {
features: 'Funcionalitats',
Expand Down Expand Up @@ -451,7 +458,9 @@ export const ca: Translations = {
builtWith: 'Fet amb Astro. Codi obert a GitHub.',
},
changelogPage: {
title: 'Changelog Envilder | Versions i actualitzacions',
title: 'Canvis d’Envilder: versions de la CLI, GitHub Action i SDKs',
description:
"Historial de versions de la CLI, GitHub Action i SDKs de runtime .NET, Python i Node.js d'Envilder.",

backToHome: "← Tornar a l'inici",
fullChangelog: 'Historial de ',
Expand All @@ -468,7 +477,9 @@ export const ca: Translations = {
categorySdkNodejs: 'Node.js',
},
docs: {
title: 'Docs Envilder | CLI, GitHub Action i AWS SSM',
title: 'Docs Envilder: secrets amb AWS SSM i Azure Key Vault',
description:
"Aprèn a resoldre variables d'entorn des d'AWS SSM Parameter Store i Azure Key Vault amb la CLI, GitHub Action i SDKs de runtime d'Envilder.",

backToHome: "← Tornar a l'inici",
pageTitle: 'Documentació',
Expand Down
19 changes: 15 additions & 4 deletions src/website/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ import type { Translations } from './types';
export const en: Translations = {
homeMeta: {
title:
'Envilder: standardize how your applications consume secrets across every environment and runtime.',
'Open-source secret management for AWS SSM and Azure Key Vault | Envilder',
description:
'Define your environment contract once and resolve it consistently across local development, CI/CD, and runtime. Using AWS SSM Parameter Store and Azure Key Vault.',
'Envilder is an open-source CLI, GitHub Action, and runtime SDK for loading secrets from AWS SSM Parameter Store and Azure Key Vault.',
},
notFound: {
title: 'Page not found | Envilder',
description: 'The requested Envilder page does not exist.',
heading: 'This page was not found',
body: 'The address may be incorrect, or the page may have moved.',
home: 'Return home',
},
nav: {
features: 'Features',
Expand Down Expand Up @@ -450,7 +457,9 @@ export const en: Translations = {
builtWith: 'Built with Astro. Open source on GitHub.',
},
changelogPage: {
title: 'Envilder Changelog | Releases & Updates',
title: 'Envilder changelog: CLI, GitHub Action, and SDK releases',
description:
'Release history for the Envilder CLI, GitHub Action, and .NET, Python, and Node.js runtime SDKs.',

backToHome: '← Back to home',
fullChangelog: 'Full ',
Expand All @@ -467,7 +476,9 @@ export const en: Translations = {
categorySdkNodejs: 'Node.js',
},
docs: {
title: 'Envilder Docs | CLI, GitHub Action & AWS SSM',
title: 'Envilder docs: AWS SSM and Azure Key Vault secrets',
description:
'Learn how to resolve environment variables from AWS SSM Parameter Store and Azure Key Vault with the Envilder CLI, GitHub Action, and runtime SDKs.',

backToHome: '← Back to home',
pageTitle: 'Documentation',
Expand Down
19 changes: 15 additions & 4 deletions src/website/src/i18n/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@ import type { Translations } from './types';
export const es: Translations = {
homeMeta: {
title:
'Envilder: estandariza cómo tus aplicaciones consumen secretos en cada entorno y runtime.',
'Gestión de secretos open source para AWS SSM y Azure Key Vault | Envilder',
description:
'Define tu contrato de entorno una vez y resuélvelo de forma consistente en desarrollo local, CI/CD y runtime. Con AWS SSM Parameter Store y Azure Key Vault.',
'Envilder es una CLI, GitHub Action y SDK de runtime open source para cargar secretos desde AWS SSM Parameter Store y Azure Key Vault.',
},
notFound: {
title: 'Página no encontrada | Envilder',
description: 'La página de Envilder solicitada no existe.',
heading: 'No hemos encontrado esta página',
body: 'La dirección puede ser incorrecta o la página puede haberse movido.',
home: 'Volver al inicio',
},
nav: {
features: 'Funcionalidades',
Expand Down Expand Up @@ -451,7 +458,9 @@ export const es: Translations = {
builtWith: 'Hecho con Astro. Código abierto en GitHub.',
},
changelogPage: {
title: 'Changelog Envilder | Versiones y actualizaciones',
title: 'Cambios de Envilder: versiones de la CLI, GitHub Action y SDKs',
description:
'Historial de versiones de la CLI, GitHub Action y SDKs de runtime .NET, Python y Node.js de Envilder.',

backToHome: '← Volver al inicio',
fullChangelog: 'Historial de ',
Expand All @@ -468,7 +477,9 @@ export const es: Translations = {
categorySdkNodejs: 'Node.js',
},
docs: {
title: 'Docs Envilder | CLI, GitHub Action y AWS SSM',
title: 'Docs Envilder: secretos con AWS SSM y Azure Key Vault',
description:
'Aprende a resolver variables de entorno desde AWS SSM Parameter Store y Azure Key Vault con la CLI, GitHub Action y SDKs de runtime de Envilder.',

backToHome: '← Volver al inicio',
pageTitle: 'Documentación',
Expand Down
11 changes: 11 additions & 0 deletions src/website/src/i18n/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ export interface FooterTranslations {

export interface ChangelogPageTranslations {
title: string;
description: string;
backToHome: string;
fullChangelog: string;
changelogAccent: string;
Expand All @@ -270,6 +271,7 @@ export interface ChangelogPageTranslations {

export interface DocsTranslations {
title: string;
description: string;
backToHome: string;
pageTitle: string;
intro: string;
Expand Down Expand Up @@ -533,6 +535,14 @@ export interface HomeMetaTranslations {
description: string;
}

export interface NotFoundTranslations {
title: string;
description: string;
heading: string;
body: string;
home: string;
}

export interface SponsorsTranslations {
title: string;
localstackAlt: string;
Expand All @@ -542,6 +552,7 @@ export interface SponsorsTranslations {

export interface Translations {
homeMeta: HomeMetaTranslations;
notFound: NotFoundTranslations;
nav: NavLinks;
theme: ThemeTranslations;
hero: HeroTranslations;
Expand Down
Loading
Loading