Skip to main content

GitHub → AWS: Show infrastructure costs

See last 30‑day AWS cost for resources tagged to this repo
🔒
https://github.com/mycompany/webshop
preload

How does this help you?

  • See the last 30 days AWS cost for infra tagged with this repository
  • Jump directly to AWS Cost Explorer pre-filtered by the repo tag

Preview

How it looks in the extension

ToolJumpcostCosts 30d: $2950 ... Other items ...

High level approach

We assume AWS resources are tagged with the repository name (tag key repository, value matching the GitHub repo, e.g. company/webshop). We then query AWS Cost Explorer for the past 30 days, filtered by that tag across all services, and sum the total cost.

Prerequisites

For the code below to work, please follow the guide on Connecting to AWS. Provide AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY as secrets.

In addition, the AWS identity used by the integration must allow querying the Cost Explorer API. At minimum, grant ce:GetCostAndUsage:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ce:GetCostAndUsage"],
"Resource": "*"
}
]
}

Code

github.aws.costs.integration.example.js
module.exports = {
metadata: {
name: 'github-aws-costs',
description: 'Show last 30 days AWS cost for resources tagged with this GitHub repository and link to Cost Explorer',
match: {
contextType: 'github',
context: {
'page.repository': { startsWith: 'my-org/' }
}
},
requiredSecrets: ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'],
cache: 300
},
run: async function (context, secrets = {}) {
// Import AWS SDK v3 Cost Explorer client only at runtime
const { CostExplorerClient, GetCostAndUsageCommand } = require('@aws-sdk/client-cost-explorer');

// Tag key and value derived from GitHub context
const tagKey = 'repository';
const tagValue = context.page.repository; // e.g. "company/webshop"

// Cost Explorer is in us-east-1
const client = new CostExplorerClient({
region: 'us-east-1',
credentials: {
accessKeyId: secrets.AWS_ACCESS_KEY_ID,
secretAccessKey: secrets.AWS_SECRET_ACCESS_KEY,
},
});

// Build a 30-day window (End is exclusive per AWS API)
function toYMD(d) {
const y = d.getUTCFullYear();
const m = String(d.getUTCMonth() + 1).padStart(2, '0');
const day = String(d.getUTCDate()).padStart(2, '0');
return `${y}-${m}-${day}`;
}
const endDate = new Date(); // today (exclusive)
const startDate = new Date();
startDate.setUTCDate(endDate.getUTCDate() - 30);

const params = {
TimePeriod: { Start: toYMD(startDate), End: toYMD(endDate) },
Granularity: 'DAILY',
Metrics: ['UnblendedCost'],
Filter: {
Tags: { Key: tagKey, Values: [tagValue] }
}
};

let total = 0;
let unit = 'USD';
let nextToken;
do {
const resp = await client.send(new GetCostAndUsageCommand({ ...params, NextPageToken: nextToken }));
if (Array.isArray(resp.ResultsByTime)) {
for (const p of resp.ResultsByTime) {
const metric = p.Total && p.Total.UnblendedCost;
if (metric && metric.Amount) {
total += parseFloat(metric.Amount);
unit = metric.Unit || unit;
}
}
}
nextToken = resp.NextPageToken;
} while (nextToken);

// Build a deep link to AWS Cost Explorer filtered by the tag and last 30 days
const ceFilter = { Tags: { Key: tagKey, Values: [tagValue] } };
const ceUrl = 'https://us-east-1.console.aws.amazon.com/cost-management/home' +
'?region=us-east-1#/cost-explorer' +
`?timeRange=LAST_30_DAYS&granularity=DAILY&costMetric=UnblendedCost&filter=${encodeURIComponent(JSON.stringify(ceFilter))}`;

// Format amount (simple two-decimal string)
const currencySymbol = unit === 'USD' ? '$' : `${unit} `;
const pretty = `${currencySymbol}${total.toFixed(2)}`;

const results = [
{ type: 'link', content: `Costs 30d: ${pretty}`, href: ceUrl }
];

return results;
}
};