Skip to content

Commit

Permalink
hardcode validCodeDomainSuffixes rather than relying on fallback ap…
Browse files Browse the repository at this point in the history
…proach at the point of read. `codeDomain` passed in the action is validated against this list.

Co-authored-by: Frederick O'Brien <[email protected]>
  • Loading branch information
twrichards and frederickobrien committed Apr 28, 2023
1 parent 440e248 commit f4ddd2e
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 19 deletions.
57 changes: 56 additions & 1 deletion cdk/__snapshots__/infra.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ cat << EOF > /etc/systemd/system/app.service
Description=Static Site service
[Service]
Environment=\\"BUCKET=",
Environment=\\"PROD_BUCKET=",
Object {
"Ref": "staticD8C87B36",
},
Expand All @@ -208,6 +208,7 @@ Environment=\\"CODE_BUCKET=",
"Ref": "codestaticB41DF3D7",
},
"\\"
Environment=\\"VALID_CODE_DOMAIN_SUFFIXES=.code.dev-gutools.co.uk\\"
Environment=\\"PORT=9000\\"
ExecStart=/app
Expand Down Expand Up @@ -1244,6 +1245,40 @@ systemctl start app
],
},
},
Object {
"Action": "s3:ListBucket",
"Condition": Object {
"StringLike": Object {
"s3:prefix": Array [
"galaxies.code.dev-gutools.co.uk/data/*",
],
},
},
"Effect": "Allow",
"Principal": Object {
"AWS": Array [
Object {
"Fn::Join": Array [
"",
Array [
"arn:",
Object {
"Ref": "AWS::Partition",
},
":iam::000000000016:root",
],
],
},
"arn:aws:iam::000000000016:role/galaxies-data-refresher-lambda-role-CODE",
],
},
"Resource": Object {
"Fn::GetAtt": Array [
"codestaticB41DF3D7",
"Arn",
],
},
},
],
"Version": "2012-10-17",
},
Expand Down Expand Up @@ -1357,6 +1392,26 @@ systemctl start app
],
},
},
Object {
"Action": "s3:ListBucket",
"Condition": Object {
"StringLike": Object {
"s3:prefix": Array [
"galaxies.gutools.co.uk/data/*",
],
},
},
"Effect": "Allow",
"Principal": Object {
"AWS": "arn:aws:iam::000000000016:role/galaxies-data-refresher-lambda-role-PROD",
},
"Resource": Object {
"Fn::GetAtt": Array [
"staticD8C87B36",
"Arn",
],
},
},
],
"Version": "2012-10-17",
},
Expand Down
4 changes: 3 additions & 1 deletion cdk/infra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ListenerAction, ListenerCondition } from 'aws-cdk-lib/aws-elasticloadba
import { AccountPrincipal, ArnPrincipal, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { Bucket } from "aws-cdk-lib/aws-s3";
import { StringParameter } from "aws-cdk-lib/aws-ssm";
import {validCodeDomainSuffixes} from "../validCodeDomainSuffixes";

interface InfraProps extends GuStackProps {
app: string;
Expand Down Expand Up @@ -63,8 +64,9 @@ cat << EOF > /etc/systemd/system/${app}.service
Description=Static Site service
[Service]
Environment="BUCKET=${prodBucket.bucketName}"
Environment="PROD_BUCKET=${prodBucket.bucketName}"
Environment="CODE_BUCKET=${codeBucket.bucketName}"
Environment="VALID_CODE_DOMAIN_SUFFIXES=${validCodeDomainSuffixes.join(',')}"
Environment="PORT=${port}"
ExecStart=/${app}
Expand Down
12 changes: 11 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -908979,13 +908979,23 @@ var StaticSite = class extends import_core.GuStack {
}
};

// validCodeDomainSuffixes.ts
var validCodeDomainSuffixes = [
".code.dev-gutools.co.uk"
];

// index.ts
var main = () => {
const app = core.getInput("app", { required: true });
const domain = core.getInput("domain", { required: true });
const codeDomain = core.getInput("codeDomain", { required: false });
const stack = "deploy";
core.info("Inputs are: " + JSON.stringify({ app, stack, domain }));
core.info("Inputs are: " + JSON.stringify({ app, stack, domain, codeDomain }));
if (codeDomain && !validCodeDomainSuffixes.some((validCodeDomainSuffix) => codeDomain.endsWith(validCodeDomainSuffix))) {
throw new Error(`${codeDomain} does not end in any of: ${validCodeDomainSuffixes.toString()}.
To add more, raise a PR in https://github.com/guardian/actions-static-site,
edit validCodeDomainSuffixes.ts, run 'npm run build' and commit the resulting JS.`);
}
const cdkApp = new import_aws_cdk_lib2.App();
const cdkStack = new StaticSite(cdkApp, "static-site", {
app,
Expand Down
11 changes: 10 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as core from "@actions/core";
import { App } from "aws-cdk-lib";
import { Template } from "aws-cdk-lib/assertions";
import { StaticSite } from "./cdk/static-site";
import {validCodeDomainSuffixes} from "./validCodeDomainSuffixes";

export const main = (): void => {
const app = core.getInput("app", { required: true });
Expand All @@ -13,9 +14,17 @@ export const main = (): void => {

core.info(
"Inputs are: " +
JSON.stringify({ app, stack, domain })
JSON.stringify({ app, stack, domain, codeDomain })
);

if(codeDomain && !validCodeDomainSuffixes.some(validCodeDomainSuffix => codeDomain.endsWith(validCodeDomainSuffix))) {
throw new Error(
`${codeDomain} does not end in any of: ${validCodeDomainSuffixes.toString()}.
To add more, raise a PR in https://github.com/guardian/actions-static-site,
edit validCodeDomainSuffixes.ts, run 'npm run build' and commit the resulting JS.`
);
}

const cdkApp = new App();
const cdkStack = new StaticSite(cdkApp, "static-site", {
app,
Expand Down
47 changes: 32 additions & 15 deletions service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http"
"os"
"path"
"strings"
"time"

"github.com/guardian/actions-static-site/service/middleware"
Expand All @@ -15,7 +16,9 @@ import (
)

type Config struct {
Port, Bucket, CodeBucket string
Port, ProdBucket, CodeBucket string

ValidCodeDomainSuffixes []string

// Override when local for easier testing.
RequireAuth bool
Expand All @@ -42,25 +45,28 @@ func optional(key, fallback string) string {

func getConfig() Config {
return Config{
Bucket: required("BUCKET"),
CodeBucket: required("CODE_BUCKET"),
Port: optional("PORT", "3333"),
RequireAuth: optional("REQUIRE_AUTH", "true") != "false",
Profile: optional("PROFILE", ""),
ProdBucket: required("PROD_BUCKET"),
CodeBucket: required("CODE_BUCKET"),
ValidCodeDomainSuffixes: strings.Split(required("VALID_CODE_DOMAIN_SUFFIXES"), ","),
Port: optional("PORT", "3333"),
RequireAuth: optional("REQUIRE_AUTH", "true") != "false",
Profile: optional("PROFILE", ""),
}
}

func main() {
config := getConfig()
store := s3.New(config.Bucket, config.Profile)
prodStore := s3.New(config.ProdBucket, config.Profile)
codeStore := s3.New(config.CodeBucket, config.Profile)

http.HandleFunc("/healthcheck", middleware.WithRequestLog(http.HandlerFunc(ok)))

handler := middleware.WithDomainPrefix(storeServer(prodStore, codeStore, config.ValidCodeDomainSuffixes))

if config.RequireAuth {
http.Handle("/", middleware.WithRequestLog(middleware.WithAuth(middleware.WithDomainPrefix(storeServer(store, codeStore)))))
http.Handle("/", middleware.WithRequestLog(middleware.WithAuth(handler)))
} else {
http.Handle("/", middleware.WithRequestLog(middleware.WithDomainPrefix(storeServer(store, codeStore))))
http.Handle("/", middleware.WithRequestLog(handler))
}

log.Printf("Server starting on http://localhost:%s.", config.Port)
Expand All @@ -72,15 +78,17 @@ func ok(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "OK")
}

func storeServer(store store.Store, fallbackStore store.Store) http.HandlerFunc {
func storeServer(prodStore store.Store, codeStore store.Store, validCodeDomainSuffixes []string) http.HandlerFunc {
return func(resp http.ResponseWriter, req *http.Request) {
key := req.URL.Path
got, err := store.Get(key)
if err != nil {
got, err = fallbackStore.Get(key)
}
host, _, _ := strings.Cut(req.Host, ":")

stageSpecificStore := getStageSpecificStore(host, prodStore, codeStore, validCodeDomainSuffixes)

got, err := stageSpecificStore.Get(key)

if err != nil {
log.Printf("unable to fetch from store for path %s and host %s: %v", req.URL.Path, req.Host, err)
log.Printf("unable to fetch from prodStore for path %s and host %s: %v", req.URL.Path, req.Host, err)
statusNotFound(resp)
}

Expand All @@ -89,6 +97,15 @@ func storeServer(store store.Store, fallbackStore store.Store) http.HandlerFunc
}
}

func getStageSpecificStore(host string, prodStore store.Store, codeStore store.Store, validCodeDomainSuffixes []string) store.Store {
for _, validCodeDomainSuffix := range validCodeDomainSuffixes {
if strings.HasSuffix(host, validCodeDomainSuffix) {
return codeStore
}
}
return prodStore
}

func statusNotFound(w http.ResponseWriter) {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintln(w, "Status Not Found (404) - resource not found.")
Expand Down
3 changes: 3 additions & 0 deletions validCodeDomainSuffixes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const validCodeDomainSuffixes = [
".code.dev-gutools.co.uk"
];

0 comments on commit f4ddd2e

Please sign in to comment.