Skip to content

Register Zendesk + support endpoint config for Contact us - #6548

Merged
zamanafzal merged 4 commits into
mainfrom
zafzal/13712-contact-us-config
Oct 26, 2026
Merged

zamanafzal merged 4 commits into
mainfrom
zafzal/13712-contact-us-config

Conversation

@zamanafzal

@zamanafzal zamanafzal commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What are the relevant tickets?

Refs https://github.com/mitodl/hq/issues/13991, under https://github.com/mitodl/hq/issues/13712

Description (What does it do?)

The Contact us support intake is merged in learn-ai (mitodl/learn-ai#98) and approved in mit-learn (mitodl/mit-learn#4139), but it does nothing in a deployed environment: no AI_ZENDESK_* setting exists in any stack, and the launcher's endpoint was never registered anywhere in this repo.

  • learn-ai QA: points AI_ZENDESK_API_URL and the three Zendesk custom field ids at the odl1791467332 sandbox, the instance local development already files against.
  • learn-ai CI/Production: adds the same four keys holding their own unset defaults, for a human to fill in from each environment's own Zendesk instance.
  • mit-learn Next.js CI/QA/Production: adds nextjs:support_endpoint, wired to NEXT_PUBLIC_LEARN_AI_SUPPORT_ENDPOINT.

The OAuth client id and secret are not here: they are secrets, and belong in src/bridge/secrets/learn_ai/secrets.{qa,production}.yaml via SOPS.

Implementation details

The Zendesk keys are spelled out in CI and Production rather than left absent so the values have an obvious home and the per-instance warning sits next to them. Those two stacks are unchanged in behavior: the committed values reproduce the defaults in learn-ai's main/settings.py.

"0" rather than "" for the unset field ids is load-bearing. get_int raises EnvironmentVariableParseException on an empty string, which would crashloop the pod at import. 0 is the sentinel _custom_fields already filters on (if field_id and value), so an unconfigured id is dropped from the payload rather than sent to Zendesk.

Field ids are minted per Zendesk instance and must not be copied between environments. Zendesk rejects the entire ticket for an id it does not recognise, whereas an unset one only drops that one value. The OAuth credentials are part of the same matched set: the token is minted at {AI_ZENDESK_API_URL}/oauth/tokens, so QA's client id and secret have to be issued by the odl1791467332 sandbox and not by another instance.

AI_ZENDESK_URL is a different setting and is deliberately untouched. It is the help center the syllabus/tutor bots link to when no article answers, defaulting to https://support.learn.mit.edu, and its hardcoded category ids belong to that help center. QA therefore reads articles from one Zendesk and files tickets into another, which is intended.

support_endpoint carries real URLs rather than placeholders: it is not a secret, and it follows the same shape as the three sibling agent endpoints already in these stacks. /ai/http/support_agent/ is already served by the existing passauth wildcard route (paths=["/ai/*"]), so no routing change is needed. It is added to all three stacks together because the siblings use require(), so a stack missing the key fails its own deploy.

CORS_ALLOW_ORIGINS is deliberately untouched. It is currently unset for learn-ai in every environment, which makes check_origin a no-op. Setting it to a non-empty list activates the origin not in allowed branch for every bot in that environment, so any origin not enumerated starts returning 403, tutor and syllabus chat included. It is not needed for the mit-learn mount, which is cross-origin but same-site, and belongs with the edX MFE work instead.

How can this be tested?

Two stacks change. A reviewer with credentials can confirm the shape of each:

cd src/ol_infrastructure/applications/learn_ai
pulumi preview -s applications.learn_ai.QA

cd src/ol_infrastructure/applications/mit_learn_nextjs
pulumi preview -s applications.mit_learn_nextjs.QA

The four added env vars should be the only change to the learn-ai pod spec. CI and Production commit the values the application already defaults to, so behavior there is unchanged. QA is the one stack with real values, and even there nothing files: with no AI_ZENDESK_OAUTH_* in the SOPS secrets file the token POST fails and the bot returns "could not file" — the same outcome as before this PR.

The mit-learn half does change something once deployed. mitodl/mit-learn#4139 merged this morning, so ContactUsLauncherGate is on main and isContactUsEnabled() reads NEXT_PUBLIC_LEARN_AI_SUPPORT_ENDPOINT directly. Setting it satisfies one of the gate's three conditions; the launcher still renders nothing until the PostHog contact-us flag is on.

I did not run either preview — no stack credentials. End-to-end filing can't be exercised from this PR either; it needs the OAuth pair, which isn't here.

Additional Context

Order matters after this merges, because the launcher appearing before Zendesk is configured gives a learner a working chat whose send fails:

  1. Add AI_ZENDESK_OAUTH_CLIENT_ID and _SECRET to the SOPS secrets file, issued by the same Zendesk instance the stack's AI_ZENDESK_API_URL points at. The VSO sync uses includes=["*"], so no policy or envFrom change is needed.
  2. For CI and Production, fill in AI_ZENDESK_API_URL and the three field ids, each taken from that environment's own Zendesk instance.
  3. Only then enable the PostHog contact-us flag for that environment.

AI_ZENDESK_STUB_MODE is left unset (defaults off) on purpose. Turning it on returns STUB-XXXXXXXX and files nothing, which is useful for exercising the conversation on RC but tells learners a ticket was filed when none was.

@agent-optibot agent-optibot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Enables MIT Learn’s frontend to call a new environment-specific support agent endpoint. Adds placeholder Zendesk configuration across Learn AI environments so support intake can be configured without changing deployments.

Key Changes

  • Configures CI, QA, and production frontend support-agent endpoints.
  • Exposes the support endpoint through Next.js public runtime configuration.
  • Adds per-environment Zendesk API and custom-field placeholders for support intake.
All Relevant File Changes (click to expand)
  • src/ol_infrastructure/applications/learn_ai/Pulumi.CI.yaml: Adds unset Zendesk API and custom-field configuration placeholders.
  • src/ol_infrastructure/applications/learn_ai/Pulumi.Production.yaml: Adds unset Zendesk API and custom-field configuration placeholders.
  • src/ol_infrastructure/applications/learn_ai/Pulumi.QA.yaml: Adds unset Zendesk API and custom-field configuration placeholders.
  • src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.CI.yaml: Configures the CI support-agent endpoint.
  • src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.Production.yaml: Configures the production support-agent endpoint.
  • src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.QA.yaml: Configures the QA support-agent endpoint.
  • src/ol_infrastructure/applications/mit_learn_nextjs/main.py: Publishes the support endpoint as a Next.js public environment variable.

💬 Feedback & Commands

Share feedback on my comments with 👍 👎 — I'll stop raising issues you push back on. Think I missed something? Adjust my sensitivity →

5 things I can do →
  • #optibot review — I'll re-review your latest changes (incremental)
  • #optibot full review — I'll re-review the entire PR from scratch
  • #optibot fix — I'll apply my suggested fixes to your code
  • #optibot compliance — I'll run a compliance check on your changes
  • #optibot release notes — I'll write up release notes for your production release

💡 Tip: Add repo-specific conventions that I'll apply to every review — Review Memory.

  • 🔄 re-review this PR

@zamanafzal
zamanafzal marked this pull request as ready for review October 23, 2026 10:51
Copilot AI balanced review requested due to automatic review settings October 23, 2026 10:51

@agent-optibot agent-optibot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Enables the Learn frontend’s support-agent integration, allowing users to submit support requests through environment-specific AI endpoints. Configures Zendesk intake settings for QA while preserving unset placeholders in CI and production until credentials and instance-specific field IDs are available.

Key Changes

  • Exposes environment-specific support-agent endpoints to the Learn frontend.
  • Configures QA to submit support requests to its Zendesk sandbox.
  • Keeps CI and production support integrations disabled until Zendesk settings are provisioned.
All Relevant File Changes (click to expand)
  • src/ol_infrastructure/applications/learn_ai/Pulumi.CI.yaml: Adds unset Zendesk endpoint and custom-field placeholders.
  • src/ol_infrastructure/applications/learn_ai/Pulumi.Production.yaml: Adds unset Zendesk endpoint and custom-field placeholders.
  • src/ol_infrastructure/applications/learn_ai/Pulumi.QA.yaml: Configures QA Zendesk sandbox endpoint and instance-specific field IDs.
  • src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.CI.yaml: Adds the CI support-agent endpoint.
  • src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.Production.yaml: Adds the production support-agent endpoint.
  • src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.QA.yaml: Adds the QA support-agent endpoint.
  • src/ol_infrastructure/applications/mit_learn_nextjs/__main__.py: Passes the configured support endpoint to frontend runtime configuration.

💬 Feedback & Commands

Share feedback on my comments with 👍 👎 — I'll stop raising issues you push back on. Think I missed something? Adjust my sensitivity →

5 things I can do →
  • #optibot review — I'll re-review your latest changes (incremental)
  • #optibot full review — I'll re-review the entire PR from scratch
  • #optibot fix — I'll apply my suggested fixes to your code
  • #optibot compliance — I'll run a compliance check on your changes
  • #optibot release notes — I'll write up release notes for your production release

💡 Tip: Add repo-specific conventions that I'll apply to every review — Review Memory.

@agent-optibot agent-optibot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status: Code Looks Good 👍

No blocking issues found.

📌 Reviewed up to the latest commit · ⏱️ Review completed in 2 minutes

  • 🔄 re-review this PR

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The additive configuration matches application contracts, covers all three stacks, and preserves feature-flag gating with no blocking issues identified.

No open issues 🎉

What changed in this PR

Registers configuration for the Contact us support flow between mit-learn and learn-ai. Ticket filing remains dependent on Zendesk credentials and configuration being completed before feature-flag activation.

Changes:

  • Configures learn-ai QA with the Zendesk sandbox URL and custom field IDs.
  • Adds explicit unset Zendesk defaults for CI and Production.
  • Registers support endpoints in all three Next.js stacks and exposes them through NEXT_PUBLIC_LEARN_AI_SUPPORT_ENDPOINT.
File Description
src/​ol_infrastructure/​applications/​mit_learn_nextjs/​Pulumi.QA.yaml Adds the RC support endpoint.
src/​ol_infrastructure/​applications/​mit_learn_nextjs/​Pulumi.Production.yaml Adds the Production support endpoint.
src/​ol_infrastructure/​applications/​mit_learn_nextjs/​Pulumi.CI.yaml Adds the CI support endpoint.
src/​ol_infrastructure/​applications/​mit_learn_nextjs/​__main__.py Maps support configuration to the public environment variable.
src/​ol_infrastructure/​applications/​learn_ai/​Pulumi.QA.yaml Sets sandbox Zendesk values and documents instance matching.
src/​ol_infrastructure/​applications/​learn_ai/​Pulumi.Production.yaml Adds unset Zendesk defaults and per-instance guidance.
src/​ol_infrastructure/​applications/​learn_ai/​Pulumi.CI.yaml Adds unset Zendesk defaults and per-instance guidance.

Review effort: Balanced

zamanafzal added a commit that referenced this pull request Oct 26, 2026
…ction

Production Zendesk is not configured yet -- AI_ZENDESK_API_URL is empty, the
three custom-field ids are "0", and no OAuth credentials exist outside QA. A
production build would ship a launcher that holds a full conversation and then
fails at send.

The MFE gate is build-time, so there is no runtime switch to pull it back: the
fix would be another build and another CI->QA->Prod promotion. Shipping rc-only
costs nothing, since rc is where the verification pass happens anyway, and
leaves one line to restore once #6548 lands.

Refs hq#14033
zamanafzal and others added 4 commits October 26, 2026 18:51
The Contact us intake (hq#13712) is merged in learn-ai and mit-learn but
does nothing in a deployed environment: no AI_ZENDESK_* setting exists in
any stack, and the launcher's endpoint was never registered.

The Zendesk keys land as placeholders holding their own "unset" defaults,
so this deploys as a no-op until someone fills them in. They are spelled
out rather than left absent so the values have an obvious home and the
per-instance warning sits next to them. Empty is not an option for the
field ids: get_int("") raises at import and would crashloop the pod, so
the sentinel is "0", which _custom_fields already skips.

support_endpoint carries real values -- it follows the same shape as its
three sibling agent endpoints, and mit-learn's gate renders nothing until
NEXT_PUBLIC_LEARN_AI_SUPPORT_ENDPOINT is set. Added to all three stacks
together because the siblings use require(), so a stack missing the key
fails its own deploy.

CORS_ALLOW_ORIGINS is deliberately untouched. An empty list makes
check_origin a no-op; a non-empty one turns it on for every bot in the
environment, which would 403 any origin not enumerated. It is not needed
for the mit-learn mount (same-site) and belongs with the edX MFE work.

Refs hq#13991
QA uses the odl1791467332 sandbox, the same instance local development
files against, so RC can exercise real ticket filing once the matching
OAuth credentials land in the SOPS secrets file. CI and Production keep
their unset defaults until each gets its own instance.
Encrypt AI_ZENDESK_OAUTH_CLIENT_ID and AI_ZENDESK_OAUTH_CLIENT_SECRET into
the learn_ai QA SOPS file. They are issued by the odl1791467332 sandbox that
the QA stack's AI_ZENDESK_API_URL points at, and reach the pod through the
existing VSO sync (includes=["*"]).
@zamanafzal
zamanafzal force-pushed the zafzal/13712-contact-us-config branch from bdb677e to e6892ad Compare October 26, 2026 13:51
@zamanafzal
zamanafzal merged commit f46833c into main Oct 26, 2026
12 checks passed
@zamanafzal
zamanafzal deleted the zafzal/13712-contact-us-config branch October 26, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants