mirror of
https://github.com/Sea-Haven-Industries/meal-order-manager.git
synced 2026-10-06 13:31:58 +00:00
fix(ci): satisfy PR policy and authorizer trust constraints
Move weekly-menu step expressions into env blocks, terraform-fmt SES alignment, and pin API Gateway authorizer invoke role assume conditions.
This commit is contained in:
parent
3906ad1885
commit
1f67543f16
2 changed files with 44 additions and 17 deletions
43
.github/workflows/weekly-menu.yml
vendored
43
.github/workflows/weekly-menu.yml
vendored
|
|
@ -28,8 +28,9 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Timezone guard
|
- name: Timezone guard
|
||||||
if: github.event_name == 'schedule'
|
if: github.event_name == 'schedule'
|
||||||
|
env:
|
||||||
|
CRON: ${{ github.event.schedule }}
|
||||||
run: |
|
run: |
|
||||||
CRON="${{ github.event.schedule }}"
|
|
||||||
OFFSET=$(TZ='America/New_York' date +%z)
|
OFFSET=$(TZ='America/New_York' date +%z)
|
||||||
echo "Cron: $CRON | Eastern offset: $OFFSET"
|
echo "Cron: $CRON | Eastern offset: $OFFSET"
|
||||||
if { [ "$OFFSET" = "-0400" ] && [ "$CRON" = "30 12 * * 1" ]; } || \
|
if { [ "$OFFSET" = "-0400" ] && [ "$CRON" = "30 12 * * 1" ]; } || \
|
||||||
|
|
@ -92,9 +93,10 @@ jobs:
|
||||||
- name: Get discount settings
|
- name: Get discount settings
|
||||||
if: env.SKIP_RUN != 'true'
|
if: env.SKIP_RUN != 'true'
|
||||||
id: discount
|
id: discount
|
||||||
|
env:
|
||||||
|
API_URL: ${{ steps.stack.outputs.api_url }}
|
||||||
run: |
|
run: |
|
||||||
SETTINGS=$(python3 scripts/upload_menu.py settings \
|
SETTINGS=$(python3 scripts/upload_menu.py settings --api-url "$API_URL")
|
||||||
--api-url "${{ steps.stack.outputs.api_url }}")
|
|
||||||
BULK=$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["bulk_discount_percent"])' "$SETTINGS")
|
BULK=$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["bulk_discount_percent"])' "$SETTINGS")
|
||||||
SUBSIDY=$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["company_subsidy_percent"])' "$SETTINGS")
|
SUBSIDY=$(python3 -c 'import json,sys; print(json.loads(sys.argv[1])["company_subsidy_percent"])' "$SETTINGS")
|
||||||
echo "bulk_discount=$BULK" >> "$GITHUB_OUTPUT"
|
echo "bulk_discount=$BULK" >> "$GITHUB_OUTPUT"
|
||||||
|
|
@ -112,42 +114,53 @@ jobs:
|
||||||
echo "Google client ID is required for cloud form generation" >&2
|
echo "Google client ID is required for cloud form generation" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "client_id=$GOOGLE_CLIENT_ID" >> $GITHUB_OUTPUT
|
echo "client_id=$GOOGLE_CLIENT_ID" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Generate order form
|
- name: Generate order form
|
||||||
if: env.SKIP_RUN != 'true'
|
if: env.SKIP_RUN != 'true'
|
||||||
|
env:
|
||||||
|
API_URL: ${{ steps.stack.outputs.api_url }}
|
||||||
|
BULK_DISCOUNT: ${{ steps.discount.outputs.bulk_discount }}
|
||||||
|
COMPANY_SUBSIDY: ${{ steps.discount.outputs.company_subsidy }}
|
||||||
|
GOOGLE_CLIENT_ID: ${{ steps.google.outputs.client_id }}
|
||||||
run: |
|
run: |
|
||||||
python3 src/server/generate_form.py \
|
python3 src/server/generate_form.py \
|
||||||
--api-url "${{ steps.stack.outputs.api_url }}" \
|
--api-url "$API_URL" \
|
||||||
--bulk-discount "${{ steps.discount.outputs.bulk_discount }}" \
|
--bulk-discount "$BULK_DISCOUNT" \
|
||||||
--company-subsidy "${{ steps.discount.outputs.company_subsidy }}" \
|
--company-subsidy "$COMPANY_SUBSIDY" \
|
||||||
--google-client-id "${{ steps.google.outputs.client_id }}"
|
--google-client-id "$GOOGLE_CLIENT_ID"
|
||||||
|
|
||||||
- name: Publish menu through API
|
- name: Publish menu through API
|
||||||
if: env.SKIP_RUN != 'true'
|
if: env.SKIP_RUN != 'true'
|
||||||
run: |
|
env:
|
||||||
python3 scripts/upload_menu.py publish \
|
API_URL: ${{ steps.stack.outputs.api_url }}
|
||||||
--api-url "${{ steps.stack.outputs.api_url }}"
|
run: python3 scripts/upload_menu.py publish --api-url "$API_URL"
|
||||||
|
|
||||||
- name: Upload form to S3
|
- name: Upload form to S3
|
||||||
if: env.SKIP_RUN != 'true'
|
if: env.SKIP_RUN != 'true'
|
||||||
|
env:
|
||||||
|
FORM_BUCKET: ${{ steps.stack.outputs.form_bucket }}
|
||||||
run: |
|
run: |
|
||||||
WEEK=$(date +%Y-W%U)
|
WEEK=$(date +%Y-W%U)
|
||||||
aws s3 cp "output/order-form-$WEEK.html" \
|
aws s3 cp "output/order-form-$WEEK.html" \
|
||||||
"s3://${{ steps.stack.outputs.form_bucket }}/index.html" \
|
"s3://${FORM_BUCKET}/index.html" \
|
||||||
--content-type "text/html" \
|
--content-type "text/html" \
|
||||||
--cache-control "no-cache"
|
--cache-control "no-cache"
|
||||||
aws s3 cp "output/order-form-$WEEK.html" \
|
aws s3 cp "output/order-form-$WEEK.html" \
|
||||||
"s3://${{ steps.stack.outputs.form_bucket }}/archive/$WEEK.html" \
|
"s3://${FORM_BUCKET}/archive/$WEEK.html" \
|
||||||
--content-type "text/html"
|
--content-type "text/html"
|
||||||
|
|
||||||
- name: Invalidate CloudFront cache
|
- name: Invalidate CloudFront cache
|
||||||
if: env.SKIP_RUN != 'true'
|
if: env.SKIP_RUN != 'true'
|
||||||
|
env:
|
||||||
|
DIST_ID: ${{ steps.stack.outputs.dist_id }}
|
||||||
run: |
|
run: |
|
||||||
aws cloudfront create-invalidation \
|
aws cloudfront create-invalidation \
|
||||||
--distribution-id "${{ steps.stack.outputs.dist_id }}" \
|
--distribution-id "$DIST_ID" \
|
||||||
--paths "/index.html"
|
--paths "/index.html"
|
||||||
|
|
||||||
- name: Notify Slack
|
- name: Notify Slack
|
||||||
if: env.SKIP_RUN != 'true'
|
if: env.SKIP_RUN != 'true'
|
||||||
run: python3 scripts/notify_slack.py "${{ steps.stack.outputs.form_url }}"
|
env:
|
||||||
|
FORM_URL: ${{ steps.stack.outputs.form_url }}
|
||||||
|
run: python3 scripts/notify_slack.py "$FORM_URL"
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,8 @@ resource "aws_iam_role_policy" "admin_authorizer" {
|
||||||
|
|
||||||
# Role API Gateway assumes to invoke the authorizer Lambda. The authorizer has
|
# Role API Gateway assumes to invoke the authorizer Lambda. The authorizer has
|
||||||
# no resource policy of its own; this identity-based grant is the only path.
|
# no resource policy of its own; this identity-based grant is the only path.
|
||||||
|
# SourceAccount + execute-api ArnLike close the confused-deputy window without
|
||||||
|
# pinning the authorizer id (that would cycle: authorizer needs this role).
|
||||||
data "aws_iam_policy_document" "apigateway_assume" {
|
data "aws_iam_policy_document" "apigateway_assume" {
|
||||||
statement {
|
statement {
|
||||||
effect = "Allow"
|
effect = "Allow"
|
||||||
|
|
@ -183,6 +185,18 @@ data "aws_iam_policy_document" "apigateway_assume" {
|
||||||
type = "Service"
|
type = "Service"
|
||||||
identifiers = ["apigateway.amazonaws.com"]
|
identifiers = ["apigateway.amazonaws.com"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
condition {
|
||||||
|
test = "StringEquals"
|
||||||
|
variable = "aws:SourceAccount"
|
||||||
|
values = [local.account_id]
|
||||||
|
}
|
||||||
|
|
||||||
|
condition {
|
||||||
|
test = "ArnLike"
|
||||||
|
variable = "aws:SourceArn"
|
||||||
|
values = ["arn:aws:execute-api:${var.aws_region}:${local.account_id}:${aws_apigatewayv2_api.order_api.id}/*"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,8 +405,8 @@ data "aws_iam_policy_document" "email_report" {
|
||||||
# Scope SendRawEmail to the verified sender domain/identity rather than "*".
|
# Scope SendRawEmail to the verified sender domain/identity rather than "*".
|
||||||
# SES still enforces verification; IAM pins the From identity ARNs.
|
# SES still enforces verification; IAM pins the From identity ARNs.
|
||||||
statement {
|
statement {
|
||||||
sid = "SendPayrollReport"
|
sid = "SendPayrollReport"
|
||||||
effect = "Allow"
|
effect = "Allow"
|
||||||
actions = ["ses:SendRawEmail"]
|
actions = ["ses:SendRawEmail"]
|
||||||
resources = [
|
resources = [
|
||||||
"arn:aws:ses:${var.aws_region}:${local.account_id}:identity/${var.sender_email}",
|
"arn:aws:ses:${var.aws_region}:${local.account_id}:identity/${var.sender_email}",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue