commit 4e5ccb2367bb06b2e768fe55ec7f07e83cc628fc Author: Scaffolder Date: Wed May 13 08:33:37 2026 +0000 initial commit Change-Id: I9ad6c3837a837ad68f28b6ea1901397a9a432227 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.DS_Store diff --git a/.gitea/workflows/cleanup.yaml b/.gitea/workflows/cleanup.yaml new file mode 100644 index 0000000..32a2498 --- /dev/null +++ b/.gitea/workflows/cleanup.yaml @@ -0,0 +1,56 @@ + +name: cleanup-expired + +on: + schedule: + - cron: "17 * * * *" + workflow_dispatch: + +jobs: + cleanup-expired: + runs-on: + - toolzoo-host + env: + AWS_REGION: us-east-1 + APP_STACK_PREFIX: temp-stack + TTL_GRACE_SECONDS: "600" + steps: + - name: Cleanup expired app stacks + shell: bash + run: | + set -euo pipefail + now_epoch="$(date -u +%s)" + prefix="${APP_STACK_PREFIX}-" + stacks="$(aws cloudformation list-stacks \ + --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE UPDATE_ROLLBACK_COMPLETE \ + --query "StackSummaries[?starts_with(StackName, \`${prefix}\`)].StackName" \ + --output text)" + + for stack in $stacks; do + expires_at="$(aws cloudformation describe-stacks --stack-name "$stack" --query "Stacks[0].Tags[?Key=='ExpiresAt'].Value | [0]" --output text)" + owner_raw="$(aws cloudformation describe-stacks --stack-name "$stack" --query "Stacks[0].Tags[?Key=='Owner'].Value | [0]" --output text)" + repo_raw="$(aws cloudformation describe-stacks --stack-name "$stack" --query "Stacks[0].Tags[?Key=='Repository'].Value | [0]" --output text)" + + if [[ "$expires_at" == "None" || -z "$expires_at" ]]; then + continue + fi + + expires_epoch="$(date -u -d "$expires_at" +%s 2>/dev/null || echo 0)" + if [[ "$expires_epoch" -eq 0 ]]; then + continue + fi + + if (( now_epoch >= expires_epoch + TTL_GRACE_SECONDS )); then + aws cloudformation delete-stack --stack-name "$stack" + aws cloudformation wait stack-delete-complete --stack-name "$stack" + + if [[ "$owner_raw" != "None" && "$repo_raw" != "None" && -n "$owner_raw" && -n "$repo_raw" ]]; then + repo_slug="$(printf '%s' "$repo_raw" | tr '[:upper:]' '[:lower:]')" + ecr_repo="temp/${repo_slug}" + if aws ecr describe-repositories --repository-names "$ecr_repo" >/dev/null 2>&1; then + aws ecr delete-repository --repository-name "$ecr_repo" --force + fi + fi + fi + done + diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml new file mode 100644 index 0000000..f2d1454 --- /dev/null +++ b/.gitea/workflows/deploy.yaml @@ -0,0 +1,217 @@ + +name: deploy + +on: + push: + branches: + - main + workflow_dispatch: + inputs: + ttl: + description: "TTL for deploy operation (1h | 4h | 24h)" + required: false + default: 1h + +jobs: + deploy: + runs-on: + - toolzoo-host + env: + BACKSTAGE_STACK_NAME: toolzoo-backstage + AWS_REGION: us-east-1 + APP_STACK_PREFIX: temp-stack + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Derive deployment settings + shell: bash + run: | + set -euo pipefail + repo_full="${GITHUB_REPOSITORY}" + owner_raw="${repo_full%%/*}" + repo_raw="${repo_full##*/}" + repo_slug="$(printf '%s' "$repo_raw" | tr '[:upper:]' '[:lower:]')" + service_slug="${repo_slug}" + stack_name="${APP_STACK_PREFIX}-${repo_slug}" + account_id="$(aws sts get-caller-identity --query Account --output text)" + image_tag="${GITHUB_SHA:-manual}" + short_tag="${image_tag:0:12}" + registry="${account_id}.dkr.ecr.${AWS_REGION}.amazonaws.com" + ecr_repo="temp/${repo_slug}" + image_uri="${registry}/${ecr_repo}:${short_tag}" + techdocs_bucket="$(aws cloudformation describe-stacks --stack-name "$BACKSTAGE_STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='TechDocsBucketName'].OutputValue" --output text)" + ttl_input="${{ github.event.inputs.ttl }}" + case "${ttl_input:-}" in + ""|"1h") ttl_hours="1" ;; + "4h") ttl_hours="4" ;; + "24h") ttl_hours="24" ;; + *) ttl_hours="1" ;; + esac + expires_at="$(date -u -d "+${ttl_hours} hour" +%Y-%m-%dT%H:%M:%SZ)" + + { + echo "TOOLZOO_OWNER=${owner_raw}" + echo "TOOLZOO_REPO=${repo_raw}" + echo "TOOLZOO_STACK_NAME=${stack_name}" + echo "TOOLZOO_SERVICE_NAME=${service_slug}" + echo "TOOLZOO_ECR_REPO=${ecr_repo}" + echo "TOOLZOO_IMAGE_URI=${image_uri}" + echo "TOOLZOO_TECHDOCS_BUCKET=${techdocs_bucket}" + echo "TOOLZOO_EXPIRES_AT=${expires_at}" + } >> "$GITHUB_ENV" + + - name: Ensure ECR repository exists + shell: bash + run: | + set -euo pipefail + aws ecr describe-repositories --repository-names "$TOOLZOO_ECR_REPO" >/dev/null 2>&1 || \ + aws ecr create-repository \ + --repository-name "$TOOLZOO_ECR_REPO" \ + --image-scanning-configuration scanOnPush=true >/dev/null + + - name: Log in to ECR + shell: bash + run: | + set -euo pipefail + aws ecr get-login-password --region "$AWS_REGION" | \ + docker login --username AWS --password-stdin "${TOOLZOO_IMAGE_URI%/*}" + + - name: Build and push container image + shell: bash + run: | + set -euo pipefail + docker build -t "$TOOLZOO_IMAGE_URI" . + docker push "$TOOLZOO_IMAGE_URI" + + - name: Deploy ECS service stack + shell: bash + run: | + set -euo pipefail + aws cloudformation deploy \ + --stack-name "$TOOLZOO_STACK_NAME" \ + --template-file infra/cloudformation/service.yaml \ + --capabilities CAPABILITY_NAMED_IAM \ + --parameter-overrides \ + EnvironmentName="$TOOLZOO_STACK_NAME" \ + ContainerImage="$TOOLZOO_IMAGE_URI" \ + ServiceName="$TOOLZOO_SERVICE_NAME" \ + --tags \ + Owner="$TOOLZOO_OWNER" \ + Repository="$TOOLZOO_REPO" \ + ExpiresAt="$TOOLZOO_EXPIRES_AT" \ + ManagedBy="gitea-actions" + + - name: Write Service URL to catalog metadata + shell: bash + run: | + set -euo pipefail + service_url="$(aws cloudformation describe-stacks --stack-name "$TOOLZOO_STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='ServiceUrl'].OutputValue" --output text)" + if [[ -z "$service_url" || "$service_url" == "None" ]]; then + echo "ServiceUrl output not found for stack $TOOLZOO_STACK_NAME" + exit 1 + fi + + printf '%s\n' \ + ' # BEGIN TOOLZOO MANAGED LINK' \ + " - url: \"$service_url\"" \ + ' title: Service URL' \ + ' icon: web' \ + ' # END TOOLZOO MANAGED LINK' \ + > /tmp/toolzoo-managed-link-item.yaml + + awk ' + BEGIN { in_block=0 } + /^ # BEGIN TOOLZOO MANAGED LINK$/ { in_block=1; next } + /^ # END TOOLZOO MANAGED LINK$/ { in_block=0; next } + in_block==1 { next } + { print } + ' catalog-info.yaml > /tmp/catalog-info.yaml.base + + if grep -q '^ links:$' /tmp/catalog-info.yaml.base; then + awk ' + BEGIN { inserted=0 } + { print } + /^ links:$/ && inserted==0 { + while ((getline l < "/tmp/toolzoo-managed-link-item.yaml") > 0) { + print l + } + close("/tmp/toolzoo-managed-link-item.yaml") + inserted=1 + } + ' /tmp/catalog-info.yaml.base > /tmp/catalog-info.yaml.updated + else + awk ' + BEGIN { inserted=0 } + /^ labels:$/ && inserted==0 { + print " links:" + while ((getline l < "/tmp/toolzoo-managed-link-item.yaml") > 0) { + print l + } + close("/tmp/toolzoo-managed-link-item.yaml") + inserted=1 + } + /^ annotations:$/ && inserted==0 { + print " links:" + while ((getline l < "/tmp/toolzoo-managed-link-item.yaml") > 0) { + print l + } + close("/tmp/toolzoo-managed-link-item.yaml") + inserted=1 + } + /^spec:$/ && inserted==0 { + print " links:" + while ((getline l < "/tmp/toolzoo-managed-link-item.yaml") > 0) { + print l + } + close("/tmp/toolzoo-managed-link-item.yaml") + inserted=1 + } + { print } + ' /tmp/catalog-info.yaml.base > /tmp/catalog-info.yaml.updated + fi + + mv /tmp/catalog-info.yaml.updated catalog-info.yaml + + - name: Commit catalog metadata update + shell: bash + run: | + set -euo pipefail + if git diff --quiet -- catalog-info.yaml; then + echo "No catalog-info.yaml changes to commit." + exit 0 + fi + git config user.name "toolzoo-bot" + git config user.email "toolzoo-bot@local" + git add catalog-info.yaml + git commit -m "Update catalog service URL from deployment output" + git push origin HEAD:main + + - name: Publish TechDocs to S3 + shell: bash + run: | + set -euo pipefail + python3 -m venv .techdocs-venv + . .techdocs-venv/bin/activate + python -m pip install --upgrade pip + python -m pip install mkdocs-techdocs-core + npx -y @techdocs/cli generate --no-docker + npx -y @techdocs/cli publish \ + --publisher-type awsS3 \ + --storage-name "$TOOLZOO_TECHDOCS_BUCKET" \ + --entity "default/Component/${TOOLZOO_REPO}" + + - name: Emit deployment summary + shell: bash + run: | + set -euo pipefail + : "${GITHUB_STEP_SUMMARY:=/tmp/toolzoo-step-summary}" + service_url="$(aws cloudformation describe-stacks --stack-name "$TOOLZOO_STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='ServiceUrl'].OutputValue" --output text)" + { + echo "Deployment stack: $TOOLZOO_STACK_NAME" + echo "Image: $TOOLZOO_IMAGE_URI" + echo "TechDocs bucket: $TOOLZOO_TECHDOCS_BUCKET" + echo "ExpiresAt (UTC): $TOOLZOO_EXPIRES_AT" + echo "Service URL: $service_url" + } | tee -a "$GITHUB_STEP_SUMMARY" + diff --git a/.gitea/workflows/destroy.yaml b/.gitea/workflows/destroy.yaml new file mode 100644 index 0000000..5cc3c68 --- /dev/null +++ b/.gitea/workflows/destroy.yaml @@ -0,0 +1,43 @@ + +name: destroy + +on: + workflow_dispatch: + inputs: + confirm_destroy: + description: "Type the repository name to confirm destroy" + required: true + default: "" + +jobs: + destroy: + runs-on: + - toolzoo-host + env: + AWS_REGION: us-east-1 + APP_STACK_PREFIX: temp-stack + steps: + - name: Destroy stack and ECR images + shell: bash + run: | + set -euo pipefail + repo_full="${GITHUB_REPOSITORY}" + owner_raw="${repo_full%%/*}" + repo_raw="${repo_full##*/}" + confirm="${{ github.event.inputs.confirm_destroy }}" + if [[ "$confirm" != "$repo_raw" ]]; then + echo "Refusing destroy: confirm_destroy must exactly match '$repo_raw'." + exit 1 + fi + + repo_slug="$(printf '%s' "$repo_raw" | tr '[:upper:]' '[:lower:]')" + stack_name="${APP_STACK_PREFIX}-${repo_slug}" + ecr_repo="temp/${repo_slug}" + + aws cloudformation delete-stack --stack-name "$stack_name" + aws cloudformation wait stack-delete-complete --stack-name "$stack_name" + + if aws ecr describe-repositories --repository-names "$ecr_repo" >/dev/null 2>&1; then + aws ecr delete-repository --repository-name "$ecr_repo" --force + fi + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..66cf341 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,6 @@ +FROM public.ecr.aws/docker/library/nginx:1.27-alpine + +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY . /usr/share/nginx/html + +EXPOSE 8080 diff --git a/README.md b/README.md new file mode 100644 index 0000000..09e23a4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# the-mardown-converter + +This repository was generated from the Backstage **Paste-and-Deploy Static Web App** template. + +## What you get + +- `index.html` written from the pasted HTML +- `assets/site.css` written from the optional CSS +- `assets/site.js` written from the optional JavaScript +- Nginx configuration +- Dockerfile serving the site on port 8080 +- Backstage `catalog-info.yaml` + +If you included separate CSS or JavaScript, make sure your HTML references: + +- `/assets/site.css` +- `/assets/site.js` + +## Run locally with Docker + +```bash +docker build -t the-mardown-converter . +docker run --rm -p 8080:8080 the-mardown-converter +``` diff --git a/assets/site.css b/assets/site.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/assets/site.css @@ -0,0 +1 @@ + diff --git a/assets/site.js b/assets/site.js new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/assets/site.js @@ -0,0 +1 @@ + diff --git a/catalog-info.yaml b/catalog-info.yaml new file mode 100644 index 0000000..b830f20 --- /dev/null +++ b/catalog-info.yaml @@ -0,0 +1,22 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: "the-mardown-converter" + description: "A markdown converter for AI agent responses" + tags: + - static + - website + - nginx + - ai + + + + annotations: + + toolzoo.io/created-by: "user:default/towhitfield@proofpoint.com" + + backstage.io/techdocs-ref: dir:. +spec: + type: website + owner: "group:default/seti" + lifecycle: experimental diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..abe658a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,18 @@ +# the-mardown-converter + +## Overview + +A markdown converter for AI agent responses + +## Operations + +- Runtime port: `8080` +- Health check path: `/` +- Deployment: Gitea Actions publishes a container image and updates the ECS service stack on pushes to `main`. +- `index.html` is written from the pasted HTML field. +- `assets/site.css` and `assets/site.js` are optional companion files for pasted CSS and JavaScript. +- After scaffold, track workflow in SETI Gitea -> Actions. + +## Ownership + +- Catalog owner: `group:default/seti` diff --git a/index.html b/index.html new file mode 100644 index 0000000..259c8eb --- /dev/null +++ b/index.html @@ -0,0 +1,603 @@ + + + + + + The Markdown Converter + + + +
+
+
+

The Markdown Converter

+

Paste Markdown on the left. Preview rich text on the right. Copy the preview into Word or another editor.

+
+
+ + + +
+
+ +
+
+
+

Markdown Input

+ Ready +
+ +
+ +
+
+

Live Preview

+ +
+
+
+
+ + +
+ + + + + diff --git a/infra/cloudformation/service.yaml b/infra/cloudformation/service.yaml new file mode 100644 index 0000000..154950e --- /dev/null +++ b/infra/cloudformation/service.yaml @@ -0,0 +1,311 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: | + Tool Zoo application service stack. Builds a dedicated ECS Fargate web service + with an internet-facing ALB and a stable CloudFormation-managed URL. + +Parameters: + EnvironmentName: + Type: String + AllowedPattern: ^[a-zA-Z0-9-]+$ + Description: Prefix used for naming resources. + + ServiceName: + Type: String + AllowedPattern: ^[a-z0-9-]+$ + Description: Logical service name used for the ECS service and log group. + + ContainerImage: + Type: String + Description: Fully-qualified container image URI to deploy. + + ContainerPort: + Type: Number + Default: 8080 + MinValue: 1 + MaxValue: 65535 + Description: Port exposed by the web container. + + HealthCheckPath: + Type: String + Default: "/" + Description: HTTP path used by the ALB health check. + + DesiredCount: + Type: Number + Default: 1 + MinValue: 1 + MaxValue: 3 + Description: Number of running tasks. + + TaskCpu: + Type: Number + Default: 512 + AllowedValues: + - 256 + - 512 + - 1024 + - 2048 + - 4096 + Description: Fargate task CPU units. + + TaskMemory: + Type: Number + Default: 1024 + AllowedValues: + - 512 + - 1024 + - 2048 + - 3072 + - 4096 + - 5120 + - 6144 + - 7168 + - 8192 + Description: Fargate task memory in MiB. + +Mappings: + SubnetConfig: + Vpc: + CIDR: 10.52.0.0/16 + PublicOne: + CIDR: 10.52.0.0/24 + PublicTwo: + CIDR: 10.52.1.0/24 + +Resources: + Vpc: + Type: AWS::EC2::VPC + Properties: + CidrBlock: !FindInMap [SubnetConfig, Vpc, CIDR] + EnableDnsHostnames: true + EnableDnsSupport: true + Tags: + - Key: Name + Value: !Sub ${EnvironmentName}-vpc + + InternetGateway: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Sub ${EnvironmentName}-igw + + VpcGatewayAttachment: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + InternetGatewayId: !Ref InternetGateway + VpcId: !Ref Vpc + + PublicSubnetOne: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref Vpc + AvailabilityZone: !Select [0, !GetAZs ''] + CidrBlock: !FindInMap [SubnetConfig, PublicOne, CIDR] + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${EnvironmentName}-public-a + + PublicSubnetTwo: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref Vpc + AvailabilityZone: !Select [1, !GetAZs ''] + CidrBlock: !FindInMap [SubnetConfig, PublicTwo, CIDR] + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${EnvironmentName}-public-b + + PublicRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref Vpc + Tags: + - Key: Name + Value: !Sub ${EnvironmentName}-public-rt + + PublicDefaultRoute: + Type: AWS::EC2::Route + DependsOn: VpcGatewayAttachment + Properties: + RouteTableId: !Ref PublicRouteTable + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref InternetGateway + + PublicSubnetOneRouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref PublicSubnetOne + + PublicSubnetTwoRouteTableAssociation: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + RouteTableId: !Ref PublicRouteTable + SubnetId: !Ref PublicSubnetTwo + + LoadBalancerSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: !Sub ${EnvironmentName} ALB ingress + VpcId: !Ref Vpc + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 80 + ToPort: 80 + CidrIp: 0.0.0.0/0 + SecurityGroupEgress: + - IpProtocol: -1 + CidrIp: 0.0.0.0/0 + + ServiceSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: !Sub ${EnvironmentName} ECS service ingress + VpcId: !Ref Vpc + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: !Ref ContainerPort + ToPort: !Ref ContainerPort + SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup + SecurityGroupEgress: + - IpProtocol: -1 + CidrIp: 0.0.0.0/0 + + ApplicationLoadBalancer: + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + Properties: + Scheme: internet-facing + Type: application + SecurityGroups: + - !Ref LoadBalancerSecurityGroup + Subnets: + - !Ref PublicSubnetOne + - !Ref PublicSubnetTwo + + ApplicationTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + Properties: + Port: !Ref ContainerPort + Protocol: HTTP + TargetType: ip + VpcId: !Ref Vpc + HealthCheckEnabled: true + HealthCheckPath: !Ref HealthCheckPath + HealthCheckProtocol: HTTP + Matcher: + HttpCode: 200-399 + + ApplicationListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + DefaultActions: + - Type: forward + TargetGroupArn: !Ref ApplicationTargetGroup + LoadBalancerArn: !Ref ApplicationLoadBalancer + Port: 80 + Protocol: HTTP + + LogGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Sub /aws/ecs/${EnvironmentName}/${ServiceName} + RetentionInDays: 14 + + Cluster: + Type: AWS::ECS::Cluster + Properties: + ClusterName: !Sub ${EnvironmentName}-cluster + + TaskExecutionRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub ${EnvironmentName}-task-exec-role + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - ecs-tasks.amazonaws.com + Action: + - sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy + + TaskRole: + Type: AWS::IAM::Role + Properties: + RoleName: !Sub ${EnvironmentName}-task-role + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - ecs-tasks.amazonaws.com + Action: + - sts:AssumeRole + + TaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: !Sub ${EnvironmentName}-taskdef + Cpu: !Ref TaskCpu + Memory: !Ref TaskMemory + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + ExecutionRoleArn: !GetAtt TaskExecutionRole.Arn + TaskRoleArn: !GetAtt TaskRole.Arn + ContainerDefinitions: + - Name: web + Image: !Ref ContainerImage + Essential: true + PortMappings: + - ContainerPort: !Ref ContainerPort + Protocol: tcp + Environment: + - Name: PORT + Value: !Sub '${ContainerPort}' + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: !Ref LogGroup + awslogs-region: !Ref AWS::Region + awslogs-stream-prefix: web + + Service: + Type: AWS::ECS::Service + DependsOn: + - ApplicationListener + Properties: + ServiceName: !Ref ServiceName + Cluster: !Ref Cluster + LaunchType: FARGATE + DesiredCount: !Ref DesiredCount + HealthCheckGracePeriodSeconds: 120 + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: ENABLED + SecurityGroups: + - !Ref ServiceSecurityGroup + Subnets: + - !Ref PublicSubnetOne + - !Ref PublicSubnetTwo + LoadBalancers: + - TargetGroupArn: !Ref ApplicationTargetGroup + ContainerName: web + ContainerPort: !Ref ContainerPort + TaskDefinition: !Ref TaskDefinition + +Outputs: + ServiceUrl: + Description: Public URL for the deployed Tool Zoo service + Value: !Sub http://${ApplicationLoadBalancer.DNSName} + + ClusterName: + Description: ECS cluster name for the deployed service + Value: !Ref Cluster diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..0725a07 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,8 @@ +site_name: the-mardown-converter +site_description: A markdown converter for AI agent responses + +nav: + - Overview: docs/index.md + +plugins: + - techdocs-core diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..bce7dc5 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,11 @@ +server { + listen 8080; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ =404; + } +}