Skip to content

ci: lock GitHub Actions with workflow lockfile - #332

Closed
JonLaliberte wants to merge 15 commits into
XeroAPI:mainfrom
JonLaliberte:ci/lock-actions
Closed

JonLaliberte wants to merge 15 commits into
XeroAPI:mainfrom
JonLaliberte:ci/lock-actions

Conversation

@JonLaliberte

Copy link
Copy Markdown

Locks GitHub Actions dependencies with workflow lockfiles to guard against moved/hijacked action tags (e.g. the tj-actions/changed-files incident).

  • uses: refs narrowed to full semver tags; exact commit SHAs recorded in .github/workflows/actions.lock (generated by gh actions-lock)
  • New actions-lock.yml workflow runs gh actions-lock --verify on PRs and pushes to the default branch
  • New dependabot.yml for github-actions: weekly, 7-day cooldown, grouped — keeps the lockfile updated

When adding or editing a workflow, run gh actions-lock to relock.

JonLaliberte and others added 15 commits April 27, 2026 14:50
Adds optional filter parameters (bankAccountId, bankTransactionIds, contactIds,
types, statuses, fromDate, toDate, modifiedAfter, where, order, pageSize) and
composes them into a Xero where-clause (OR within group, AND between groups,
user-supplied where wrapped in its own parens). Validates GUIDs, dates, and
modifiedAfter at the handler boundary; passes modifiedAfter through as
If-Modified-Since. Existing callers using only page and/or bankAccountId remain
backward-compatible; no-arg behaviour is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Currently, authenticate() fetches a new token from Xero's identity
server on every single tool call. This is wasteful and can trigger
rate limiting on long-running sessions, causing 'Failed to get Xero
token' errors.

This change caches the token and tracks its expiry using the
expires_in value from Xero's response. The token is only refreshed
when it's within 5 minutes of expiring, reducing unnecessary calls
to the identity endpoint from dozens per session to ~1 per 25 minutes.
This fixes two issues that caused server crashes on API errors:

1. Missing await in updateBankTransaction: The API call was fire-and-forget,
   causing unhandled promise rejections when the Xero API returned errors.
   Now properly awaits and returns the actual response.

2. Enhanced error handling for 400 validation errors: Added extraction of
   Xero validation error messages from Elements[0].ValidationErrors to
   provide meaningful error messages instead of generic failures.

Fixes XeroAPI#104
… README.

- Updated the `list-invoices` tool to support advanced filtering capabilities, including a required 'where' parameter for invoice types and additional filtering options for statuses, dates, and amounts.
- Refactored the `getInvoices` function to accept a single parameter object for better clarity and usability.
- Revised the README to reflect the new advanced filtering features for the `list-invoices` command.
Add two new read-only tools for accessing Xero invoice documents:

- get-invoice-online-url: returns the public shareable URL for an invoice
  (gracefully handles invoices without online viewing enabled)
- get-invoice-as-pdf: returns the Xero-rendered invoice PDF as base64

Both use existing accounting.transactions scope — no new scopes required.
Add get-history and add-note tools for Invoices, Contacts, CreditNotes,
BankTransactions, and Quotes using a shared handler factory.

- src/handlers/history-handler-factory.ts: DRY factory with getEntityHistory()
  and addEntityNote() that accept entity-specific SDK method references
- src/tools/history/index.ts: Generates 10 tools (get + add for each entity)
  via createGetHistoryTool() and createAddNoteTool() factories
- Tool descriptions warn that notes are immutable (cannot be edited or deleted)
- Registered HistoryTools in tool-factory.ts
The listXeroProfitAndLoss wrapper was omitting the standardLayout
argument when calling fetchProfitAndLoss, causing paymentsOnly to land
in the standardLayout positional slot and never reach the Xero API.

Fixes XeroAPI#138
- list-organisation-details: move fallback text inside template
  interpolations so '|| "No ... available."' no longer leaks into output;
  render payment terms as day + type instead of [object Object]
- formatLineItem: render tracking as 'Category: Option', read item ID from
  item.itemID, omit item ID/code/tracking when absent
- list-bank-transactions / list-invoices: separate line items with blank
  lines instead of the default comma join
getExternalLink ran encodeURIComponent over the whole URL, so links
rendered as https%3A%2F%2F... Print the URL as-is and drop the helper,
which had no other callers.
* feat: optional HTTP mode with a Xero token per request

XERO_MCP_TRANSPORT=http serves Streamable HTTP (stateless). Each request brings its own Xero
access token (Authorization: Bearer), optional Xero-Tenant-Id header; no credentials on the
server, so an MCP gateway can run the Xero OAuth flow (standard app, no custom connection).

Handlers are unchanged: xeroClient resolves to the request's client (AsyncLocalStorage) or,
outside a request, to the env-configured client as before. Stdio stays the default and still
checks env credentials at startup. History tools reference AccountingApi prototype methods
instead of reading the client at import time. Adds a Dockerfile for HTTP mode.

* feat(http): serve discovery without a token; only tool calls need one

Gateways health-check and list tools without a user's Xero token (ContextForge deactivated
the backend after three 401s). Also fixes a lint error in the request-scoping test.
Pin actions to full semver tags with SHAs recorded in
.github/workflows/actions.lock, verify it in CI, and add Dependabot
(7-day cooldown) to keep it current.
@JonLaliberte

Copy link
Copy Markdown
Author

Opened against the wrong repo by mistake — sorry for the noise.

@JonLaliberte
JonLaliberte deleted the ci/lock-actions branch November 11, 2026 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants