Skip to content
8 changes: 8 additions & 0 deletions docs/test/001-security-txt/01-curl-security-txt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Set-Cookie: shop_session-id=a58b718d-cbf3-4842-9d71-157cb61986c0; Max-Age=172800
Date: Mon, 20 Jul 2026 12:43:01 GMT
Content-Length: 67

Contact: mailto:security@example.com
Expires: 2027-01-20T12:43:01Z
292 changes: 292 additions & 0 deletions docs/test/001-security-txt/02-home-sanity.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
HTTP/1.1 200 OK
Set-Cookie: shop_session-id=71f1d4ac-aec0-45f6-ad4f-d9f13f48bb6b; Max-Age=172800
Date: Mon, 20 Jul 2026 12:43:04 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked




<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>

Online Boutique

</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB"
crossorigin="anonymous">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Google+Symbols:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet" />
<link rel="stylesheet" type="text/css" href="/static/styles/styles.css">
<link rel="stylesheet" type="text/css" href="/static/styles/cart.css">
<link rel="stylesheet" type="text/css" href="/static/styles/order.css">
<link rel="stylesheet" type="text/css" href="/static/styles/bot.css">

<link rel='shortcut icon' type='image/x-icon' href='/static/favicon.ico' />

</head>

<body>
<header>

<div class="navbar sub-navbar">
<div class="container d-flex justify-content-between">
<a href="/" class="navbar-brand d-flex align-items-center">

<img src="/static/icons/Hipster_NavLogo.svg" alt="" class="top-left-logo" />

</a>
<div class="controls">


<div class="h-controls">
<div class="h-control">
<span class="icon currency-icon"> $</span>
<form method="POST" class="controls-form" action="/setCurrency" id="currency_form" >
<select name="currency_code" onchange="document.getElementById('currency_form').submit();">

<option value="EUR" >EUR</option>

<option value="USD" selected="selected">USD</option>

<option value="JPY" >JPY</option>

<option value="GBP" >GBP</option>

<option value="TRY" >TRY</option>

<option value="CAD" >CAD</option>

</select>
</form>
<img src="/static/icons/Hipster_DownArrow.svg" alt="" class="icon arrow" />
</div>
</div>




<a href="/cart" class="cart-link">
<img src="/static/icons/Hipster_CartIcon.svg" alt="Cart icon" class="logo" title="Cart" />

</a>
</div>
</div>
</div>

</header>

<div class="local" >
<span class="platform-flag">
local
</span>
</div>
<main role="main" class="home">


<div class="home-mobile-hero-banner d-lg-none"></div>

<div class="container-fluid">
<div class="row">






<div class="col-12 col-lg-12 px-10-percent">

<div class="row hot-products-row px-xl-6">

<div class="col-12">
<h3>Hot Products</h3>
</div>


<div class="col-md-4 hot-product-card">
<a href="/product/OLJCESPC7Z">
<img loading="lazy" src="/static/img/products/sunglasses.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Sunglasses</div>
<div class="hot-product-card-price">$19.99</div>
</div>
</div>

<div class="col-md-4 hot-product-card">
<a href="/product/66VCHSJNUP">
<img loading="lazy" src="/static/img/products/tank-top.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Tank Top</div>
<div class="hot-product-card-price">$18.99</div>
</div>
</div>

<div class="col-md-4 hot-product-card">
<a href="/product/1YMWWN1N4O">
<img loading="lazy" src="/static/img/products/watch.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Watch</div>
<div class="hot-product-card-price">$109.99</div>
</div>
</div>

<div class="col-md-4 hot-product-card">
<a href="/product/L9ECAV7KIM">
<img loading="lazy" src="/static/img/products/loafers.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Loafers</div>
<div class="hot-product-card-price">$89.99</div>
</div>
</div>

<div class="col-md-4 hot-product-card">
<a href="/product/2ZYFJ3GM2N">
<img loading="lazy" src="/static/img/products/hairdryer.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Hairdryer</div>
<div class="hot-product-card-price">$24.99</div>
</div>
</div>

<div class="col-md-4 hot-product-card">
<a href="/product/0PUK6V6EV0">
<img loading="lazy" src="/static/img/products/candle-holder.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Candle Holder</div>
<div class="hot-product-card-price">$18.99</div>
</div>
</div>

<div class="col-md-4 hot-product-card">
<a href="/product/LS4PSXUNUM">
<img loading="lazy" src="/static/img/products/salt-and-pepper-shakers.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Salt &amp; Pepper Shakers</div>
<div class="hot-product-card-price">$18.49</div>
</div>
</div>

<div class="col-md-4 hot-product-card">
<a href="/product/9SIQT8TOJO">
<img loading="lazy" src="/static/img/products/bamboo-glass-jar.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Bamboo Glass Jar</div>
<div class="hot-product-card-price">$5.49</div>
</div>
</div>

<div class="col-md-4 hot-product-card">
<a href="/product/6E92ZMYYFZ">
<img loading="lazy" src="/static/img/products/mug.jpg">
<div class="hot-product-card-img-overlay"></div>
</a>
<div>
<div class="hot-product-card-name">Mug</div>
<div class="hot-product-card-price">$8.99</div>
</div>
</div>


</div>


<div class="row d-none d-lg-block home-desktop-footer-row">
<div class="col-12 p-0">


<footer class="py-5">
<div class="footer-top">
<div class="container footer-social">
<p class="footer-text">This website is hosted for demo purposes only. It is not an actual shop. This is not a Google product.</p>
<p class="footer-text">© 2020-2026 Google LLC (<a href="https://github.com/GoogleCloudPlatform/microservices-demo">Source Code</a>)</p>
<p class="footer-text">
<small>
session-id: 71f1d4ac-aec0-45f6-ad4f-d9f13f48bb6b —
request-id: a96844e6-7da3-47c2-ba9e-51639c2ffbd5
</small>
<br/>
<small>

Deployment details are still loading.
Try refreshing this page.

</small>
</p>
</div>
</div>
</footer>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"
integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous">
</script>
</body>

</html>

</div>
</div>

</div>

</div>
</div>

</main>


<div class="d-lg-none">


<footer class="py-5">
<div class="footer-top">
<div class="container footer-social">
<p class="footer-text">This website is hosted for demo purposes only. It is not an actual shop. This is not a Google product.</p>
<p class="footer-text">© 2020-2026 Google LLC (<a href="https://github.com/GoogleCloudPlatform/microservices-demo">Source Code</a>)</p>
<p class="footer-text">
<small>
session-id: 71f1d4ac-aec0-45f6-ad4f-d9f13f48bb6b —
request-id: a96844e6-7da3-47c2-ba9e-51639c2ffbd5
</small>
<br/>
<small>

Deployment details are still loading.
Try refreshing this page.

</small>
</p>
</div>
</div>
</footer>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"
integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous">
</script>
</body>

</html>

</div>

97 changes: 97 additions & 0 deletions docs/test/001-security-txt/summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Live e2e smoke — unit 001-security-txt (service: frontend)

**Branch:** work/001-security-txt
**Verdict: PASS**

## What was proven
`GET /.well-known/security.txt` on the live, freshly-deployed `frontend` service returns HTTP 200,
`Content-Type: text/plain; charset=utf-8`, a `Contact: mailto:security@example.com` line, and
exactly one `Expires:` line with an RFC 3339 timestamp ~6 months in the future. The storefront
home page still serves 200 after the redeploy.

## Bring-up (why this is a real test, not the stale pod)
The running `frontend` pod predated the change (image built ~4 days ago, no new endpoint), so the
following was done before smoking the endpoint:

1. `docker build -t frontend:e2e-001-securitytxt src/frontend` — **PASS**, image built successfully
from the current `work/001-security-txt` source (Go build completed, image exported as
`frontend:e2e-001-securitytxt`).
2. `kind load docker-image frontend:e2e-001-securitytxt --name boutique` — **PASS**, image loaded
onto node `boutique-control-plane`.
3. `kubectl set image deployment/frontend server=frontend:e2e-001-securitytxt` (container name
confirmed via `kubectl get deployment frontend -o jsonpath='{.spec.template.spec.containers[*].name}'`
→ `server`) — **PASS**, deployment updated.
4. `kubectl rollout status deployment/frontend --timeout=180s` — **PASS**:
```
deployment.apps/frontend image updated
Waiting for deployment "frontend" rollout to finish: 1 old replicas are pending termination...
deployment "frontend" successfully rolled out
```
New pod `frontend-567f6d6bbb-kwjjq` came up `Running 1/1` on the new image (confirms the kind
node pulled the locally-loaded image, not a stale cached one — otherwise the rollout would have
stuck on `ImagePullBackOff`).
5. `kubectl port-forward deployment/frontend 8080:8080` (backgrounded) — **PASS**, forwarding
established (`Forwarding from [::1]:8080 -> 8080`).

## Step 1 — `GET /.well-known/security.txt` — PASS

**Input sent:**
```
curl -isS http://localhost:8080/.well-known/security.txt
```

**Observed output** (full response, see [`01-curl-security-txt.txt`](./01-curl-security-txt.txt)):
```
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Set-Cookie: shop_session-id=a58b718d-cbf3-4842-9d71-157cb61986c0; Max-Age=172800
Date: Mon, 20 Jul 2026 12:43:01 GMT
Content-Length: 67

Contact: mailto:security@example.com
Expires: 2027-01-20T12:43:01Z
```

Assertion checks:
- **Status 200** — PASS (`HTTP/1.1 200 OK`).
- **`Content-Type: text/plain; charset=utf-8`** — PASS, present verbatim in headers.
- **Body contains `Contact: mailto:security@example.com`** — PASS, present verbatim in body.
- **Exactly one `Expires:` line, RFC 3339, in the future (~6 months out)** — PASS.
`grep -c '^Expires:'` → `1`. Value `2027-01-20T12:43:01Z` parses as RFC 3339 (`YYYY-MM-DDTHH:MM:SSZ`).
Current time at capture was `2026-07-20T12:43:10Z` (via `date -u`), so the `Expires` value is
~6 months in the future, consistent with the expected ~6-month-out policy.

## Step 2 — Storefront sanity (`GET /`) — PASS

**Input sent:**
```
curl -isS http://localhost:8080/
```

**Observed output** (see [`02-home-sanity.txt`](./02-home-sanity.txt), truncated to headers +
top of body):
```
HTTP/1.1 200 OK
Set-Cookie: shop_session-id=71f1d4ac-aec0-45f6-ad4f-d9f13f48bb6b; Max-Age=172800
Date: Mon, 20 Jul 2026 12:43:04 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked

<!DOCTYPE html>
<html lang="en">
...
<title>
Online Boutique
```

- **Status 200, HTML storefront rendered** — PASS. Confirms the redeploy of the new frontend
image did not break the app.

## Cleanup
The backgrounded `kubectl port-forward` process was terminated after capturing evidence
(`pkill -f "kubectl port-forward deployment/frontend"`); no forwarding left running.

## Conclusion
All 4 required assertions on `/.well-known/security.txt` hold, and the storefront home page still
serves correctly after the frontend was rebuilt/redeployed from the `work/001-security-txt`
branch. **Verdict: PASS.**
Loading