Skip to content

Commit 26467e1

Browse files
authored
Merge pull request #8 from csharpfritz/copilot/fix-7
2 parents 9323983 + 4a60122 commit 26467e1

9 files changed

Lines changed: 101 additions & 1 deletion

File tree

.github/workflows/azure-dev.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
name: Build and Deploy
22

3-
# Run when commits are pushed to main
3+
# Run when commits are pushed to main (excluding Content folder changes)
44
on:
55
workflow_dispatch:
66
push:
77
# Run when commits are pushed to mainline branch (main or master)
88
# Set this to the mainline branch you are using
99
branches:
1010
- main
11+
# Exclude Content folder changes to avoid unnecessary deployments
12+
paths-ignore:
13+
- 'Content/**'
1114

1215
# Set up permissions for deploying with secretless Azure federated credentials
1316
# https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Clinux#set-up-azure-login-with-openid-connect-authentication
@@ -25,6 +28,7 @@ jobs:
2528
AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
2629
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
2730
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
31+
CACHE_REFRESH_API_KEY: ${{ secrets.CACHE_REFRESH_API_KEY }}
2832

2933
steps:
3034
- name: Checkout

.github/workflows/content-sync.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,30 @@ jobs:
3636
AZURE_STORAGE_CONNECTION_STRING: ${{ secrets.CONTENT_STORAGE_CONNECTION_STRING }}
3737
run: dotnet run --project ContentLoader/ContentLoader.csproj --configuration Release -- Content
3838

39+
- name: Refresh Web App Cache
40+
if: success()
41+
env:
42+
CACHE_REFRESH_API_KEY: ${{ secrets.CACHE_REFRESH_API_KEY }}
43+
run: |
44+
echo "Refreshing web application cache..."
45+
# Wait a moment for the content to be fully uploaded
46+
sleep 5
47+
48+
# Call the cache refresh endpoint with API key authentication
49+
response=$(curl -s -w "%{http_code}" -X POST "https://copilotthatjawn.com/api/cache/refresh" \
50+
-H "X-API-Key: $CACHE_REFRESH_API_KEY" \
51+
-o /tmp/cache_response.json)
52+
53+
if [ "$response" = "200" ]; then
54+
echo "Cache refresh successful"
55+
cat /tmp/cache_response.json
56+
else
57+
echo "Cache refresh failed with HTTP status: $response"
58+
cat /tmp/cache_response.json || echo "No response body"
59+
# Don't fail the workflow if cache refresh fails - it's not critical
60+
echo "Continuing workflow despite cache refresh failure..."
61+
fi
62+
3963
- name: Handle Failure
4064
if: failure()
4165
run: |

AppHost/infra/web.tmpl.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ properties:
3030
secrets:
3131
- name: connectionstrings--tables
3232
value: '{{ .Env.AZURE_STORAGE_TABLEENDPOINT }}'
33+
- name: cacherefresh--apikey
34+
value: '{{ .Env.CACHE_REFRESH_API_KEY }}'
3335
template:
3436
containers:
3537
- image: {{ .Image }}
@@ -49,6 +51,8 @@ properties:
4951
value: in_memory
5052
- name: ConnectionStrings__tables
5153
secretRef: connectionstrings--tables
54+
- name: CacheRefresh__ApiKey
55+
secretRef: cacherefresh--apikey
5256
scale:
5357
minReplicas: 1
5458
tags:

Web/Extensions/EndpointExtensions.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,4 +192,57 @@ public static class EndpointExtensions
192192
.SetVaryByHost(true)
193193
.Tag("rss"));
194194
}
195+
196+
public static void MapCacheRefreshEndpoint(this WebApplication app)
197+
{
198+
app.MapPost("/api/cache/refresh", async (HttpContext context, IContentService contentService, ILogger<Program> logger, IWebHostEnvironment environment, IConfiguration configuration) =>
199+
{
200+
try
201+
{
202+
logger.LogInformation("Cache refresh requested via API endpoint");
203+
204+
// Validate API key for security
205+
var expectedApiKey = configuration["CacheRefresh:ApiKey"];
206+
if (!string.IsNullOrEmpty(expectedApiKey))
207+
{
208+
var providedApiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
209+
if (string.IsNullOrEmpty(providedApiKey) || providedApiKey != expectedApiKey)
210+
{
211+
logger.LogWarning("Cache refresh request rejected: Invalid or missing API key");
212+
return Results.Unauthorized();
213+
}
214+
}
215+
else if (!environment.IsDevelopment())
216+
{
217+
logger.LogWarning("Cache refresh API key not configured in production environment");
218+
return Results.Problem("API key not configured", statusCode: 500);
219+
}
220+
221+
// Only perform cache refresh in non-development environments
222+
// In development, the cache isn't as critical and may require Azure Table Storage
223+
if (environment.IsDevelopment())
224+
{
225+
logger.LogInformation("Development environment detected. Skipping cache refresh.");
226+
return Results.Ok(new {
227+
message = "Cache refresh skipped in development environment",
228+
timestamp = DateTime.UtcNow,
229+
environment = "Development"
230+
});
231+
}
232+
233+
await contentService.RefreshContentAsync();
234+
235+
logger.LogInformation("Cache refresh completed successfully");
236+
return Results.Ok(new { message = "Cache refreshed successfully", timestamp = DateTime.UtcNow });
237+
}
238+
catch (Exception ex)
239+
{
240+
logger.LogError(ex, "Error refreshing cache via API endpoint");
241+
return Results.Problem("Failed to refresh cache", statusCode: 500);
242+
}
243+
})
244+
.WithName("RefreshCache")
245+
.WithSummary("Refresh the content cache")
246+
.WithDescription("Triggers a refresh of the in-memory content cache from Azure Table Storage. Requires X-API-Key header for authentication.");
247+
}
195248
}

Web/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@
156156
app.MapSitemapEndpoint();
157157
app.MapRssFeedEndpoint();
158158

159+
// Map cache refresh endpoint
160+
app.MapCacheRefreshEndpoint();
161+
159162
app.MapDefaultEndpoints();
160163

161164
app.Run();

infra/main.bicep

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ param location string
1212
@description('Id of the user or app to assign application roles')
1313
param principalId string = ''
1414

15+
@description('API key for cache refresh endpoint security')
16+
@secure()
17+
param cacheRefreshApiKey string = ''
18+
1519

1620
var tags = {
1721
'azd-env-name': environmentName
@@ -29,6 +33,7 @@ module resources 'resources.bicep' = {
2933
location: location
3034
tags: tags
3135
principalId: principalId
36+
cacheRefreshApiKey: cacheRefreshApiKey
3237
}
3338
}
3439

infra/main.parameters.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
},
1111
"location": {
1212
"value": "${AZURE_LOCATION}"
13+
},
14+
"cacheRefreshApiKey": {
15+
"value": "${CACHE_REFRESH_API_KEY}"
1316
}
1417
}
1518
}

infra/resources.bicep

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ param location string = resourceGroup().location
33
@description('Id of the user or app to assign application roles')
44
param principalId string = ''
55

6+
@description('API key for cache refresh endpoint security')
7+
@secure()
8+
param cacheRefreshApiKey string = ''
9+
610

711
@description('Tags that will be applied to all resources')
812
param tags object = {}

packages-microsoft-prod.deb

3.61 KB
Binary file not shown.

0 commit comments

Comments
 (0)