Skip to content

feat: remove Mako and CherryPy#1998

Open
wtobis-splunk wants to merge 8 commits intodevelopfrom
feat/remove-mako-and-cherrypy
Open

feat: remove Mako and CherryPy#1998
wtobis-splunk wants to merge 8 commits intodevelopfrom
feat/remove-mako-and-cherrypy

Conversation

@wtobis-splunk
Copy link
Copy Markdown

@wtobis-splunk wtobis-splunk commented Mar 17, 2026

Issue number:
ADDON-86196

PR Type

What kind of change does this PR introduce?

  • Feature
  • Bug Fix
  • Refactoring (no functional or API changes)
  • Documentation Update
  • Maintenance (dependency updates, CI, etc.)

Summary

This PR removes Mako syntax and CherryPy-dependent runtime logic from the generated app templates used by UCC add-ons.

The original base.html and redirect.html templates relied on Mako constructs (<%! %>, <% %>, ${...}) and on cherrypy.request.path_info to resolve the app name and asset paths at render time. This caused AppInspect issues and made the templates depend on Splunk Web template execution details.

After this change, the generated templates are plain HTML only. App-specific values are injected during build, and the Splunk bootstrap scripts are loaded through static relative paths so the UI still initializes correctly without any Mako expressions in the templates.

Changes

base.html

  • rewritten as plain HTML with no Mako syntax
  • loads Splunk bootstrap scripts through relative paths from <head>
  • loads entry_page.js through a static relative path with __APP_NAME__ replaced during build

redirect.html

  • rewritten as plain HTML with no Mako syntax
  • loads Splunk bootstrap scripts through relative paths from <head>
  • loads the redirect bundle through a static relative path with __APP_NAME__, __TA_NAME__, and __TA_VERSION__ replaced during build

build.py

  • preserves real app name casing in generated static asset paths
  • applies placeholder replacement after package files are copied, so generated output is not overwritten
  • updates OAuth redirect template replacement to match the new static template format

package_files_update.py

  • removes obsolete Mako migration logic that is no longer needed for the new templates

Tests / fixtures

  • updates smoke expected output and source fixtures to match the final generated templates
  • adds unit coverage for the new build paths and no-op branches
  • keeps UI tests passing by restoring the required Splunk bootstrap sequence without reintroducing Mako expressions

User experience

Before:

  • generated UCC templates depended on Mako / CherryPy runtime behavior
  • static asset paths were partially resolved at render time
  • AppInspect reported Python code blocks in Mako templates

After:

  • generated templates are plain HTML only
  • required Splunk bootstrap resources are still loaded, so UCC UI pages behave as before
  • AppInspect no longer sees Python/Mako template code in these files

Checklist

If an item does not apply to your changes, leave it unchecked.

Review

  • self-review - I have performed a self-review of this change according to the development guidelines
  • Changes are documented. The documentation is understandable, examples work (more info)
  • PR title and description follows the contributing principles
  • meeting - I have scheduled a meeting or recorded a demo to explain these changes (if there is a video, put a link below and in the ticket)

Tests

See the testing doc.

  • Unit - tests have been added/modified to cover the changes
  • Smoke - tests have been added/modified to cover the changes
  • UI - tests have been added/modified to cover the changes
  • coverage - I have checked the code coverage of my changes (see more)

Demo/meeting:

Reviewers are encouraged to request meetings or demos if any part of the change is unclear

@wtobis-splunk wtobis-splunk force-pushed the feat/remove-mako-and-cherrypy branch from abbfa0f to fd2f7c0 Compare March 19, 2026 09:15
@wtobis-splunk wtobis-splunk force-pushed the feat/remove-mako-and-cherrypy branch from fd2f7c0 to 689de4f Compare March 19, 2026 09:43
@wtobis-splunk wtobis-splunk force-pushed the feat/remove-mako-and-cherrypy branch 3 times, most recently from 61da780 to 2ceb3f5 Compare March 19, 2026 15:54
@wtobis-splunk wtobis-splunk force-pushed the feat/remove-mako-and-cherrypy branch from 2ceb3f5 to 57fe298 Compare March 19, 2026 16:04
Copy link
Copy Markdown
Contributor

@soleksy-splunk soleksy-splunk left a comment

Choose a reason for hiding this comment

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

some comments

<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
<base >
<base href="../../" />
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.

here i wouldn't recommend to change the base url but modify all other calls, as this might be problematic for any other calls

so i would put ../../ before any other scr
../../config?autoload=1
../../static/js/i18n.js
../../i18ncatalog?autoload=1
../../static/app/Splunk_TA_UCCExample/js/build/entry_page.js

it should still work but it wont modify any other calls that are there.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch — you're right that <base href> affects all relative references on the page, not just the ones we control. Switched to explicit ../../ prefixes on each src attribute instead. The change was straightforward since this approach was already validated in an earlier iteration of this PR (commit 689de4f).

<base href="../../" />
<script src="config?autoload=1" crossorigin="use-credentials"></script>
<script src="static/js/i18n.js"></script>
<script src="i18ncatalog?autoload=1"></script>
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.

pointing it out to make sure to test it,
here is a slight behaviour change regarding Splunk caching mechanism

before:
every app pointed to (hash changed from time to time):
http://localhost:8000/en-GB/static/@4D5115C2BBEDBE564FA527CC44093F940E617B8AF35782CBC9A44889DB0D66FB.83/js/i18n.js
now every app fetches
http://localhost:8000/en-GB/static/js/i18n.js

after a brief AI questions about differences:

whats the difference between those 2 links:

The difference between these two URLs is the cache-busting hash in the second URL:

http://localhost:8000/en-GB/static/js/i18n.js

Direct path to the static file
No versioning or cache control
http://localhost:8000/en-GB/static/@4D5115C2BBEDBE564FA527CC44093F940E617B8AF35782CBC9A44889DB0D66FB.83/js/i18n.js

Contains a hash: @4D5115C2BBEDBE564FA527CC44093F940E617B8AF35782CBC9A44889DB0D66FB.83
This is a content hash or build hash used for cache busting
Why Splunk uses the hash:
Cache Busting: When the file content changes, the hash changes, forcing browsers to download the new version instead of using cached content
Long-term Caching: Splunk can set aggressive cache headers (cache forever) because the URL will change when content changes
Version Control: The .83 might indicate a Splunk version number
Performance: Browsers can safely cache these files indefinitely without worrying about stale content
How it works:
Both URLs serve the same file, but Splunk's web server (typically Splunkd or Cherrypy) intercepts requests with the @HASH pattern and strips it out before serving the actual file. The hash itself doesn't correspond to a real directory—it's middleware that handles the routing.

This is a common pattern in modern web applications (similar to webpack's [contenthash] or other build tools) to ensure optimal caching while preventing stale resources.

what is the problem if i will be using the version without hashes

If you use the version without hashes, you'll face several potential problems:

1. Browser Caching Issues (Most Critical)
Stale Content: Browsers will cache i18n.js and may not fetch the updated version even after you deploy changes
User Experience: Users might see old UI behavior, broken functionality, or outdated translations
Hard Refresh Required: Users would need to manually clear cache or do hard refresh (Ctrl+F5) to see updates
2. Version Mismatch Problems
Mixed Versions: If your HTML updates but cached JS doesn't, you can get:
JavaScript errors
Missing functions/methods
Broken API calls
UI rendering issues
3. Splunk-Specific Issues
App Updates: When you upgrade your Splunk app, users might continue using old JavaScript files
Configuration Changes: If your globalConfig.json or other configs change, the old JS might not handle them correctly
Development Pain: During development, you'll constantly fight browser cache
4. Cache Control Challenges
Without hashes, you'd need to:

Set short cache expiration times (slower page loads)
OR risk serving stale content (broken functionality)
No good middle ground
Workarounds (if you can't use hashes):

<!-- Query string versioning -->
<script src="/static/js/i18n.js?v=1.2.3"></script>

<!-- Timestamp -->
<script src="/static/js/i18n.js?t=1234567890"></script>

<!-- App version -->
<script src="/static/js/i18n.js?v=${app_version}"></script>
But these are inferior to content hashing because:

Version bumps happen even if the file didn't change
Requires manual version management
Less reliable than content-based hashing
Bottom line: The hash ensures users always get the correct version of your JavaScript that matches your current app deployment. It's a best practice for production web applications.

if i wont use hashes how will the upgrade Splunk Enterprise itself (e.g., 8.2 → 8.3 → 9.0) loook like from the file i18.js perspective

Scenario: Upgrading Splunk 8.2 → 9.0
WITH Hashes (Normal Splunk behavior):

Before upgrade (Splunk 8.2):
http://localhost:8000/en-GB/static/@HASH82.82/js/i18n.js
↓
Splunk 8.2 upgraded to 9.0
↓
After upgrade (Splunk 9.0):
http://localhost:8000/en-GB/static/@HASH90.90/js/i18n.js
What happens:

User visits app after upgrade
Browser sees new URL with different hash
Browser: "Oh, this is a NEW file" → downloads fresh version
✅ User gets Splunk 9.0's updated i18n.js immediately
WITHOUT Hashes (Your scenario):

Before upgrade (Splunk 8.2):
http://localhost:8000/en-GB/static/js/i18n.js
↓
Splunk 8.2 upgraded to 9.0
↓
After upgrade (Splunk 9.0):
http://localhost:8000/en-GB/static/js/i18n.js  (SAME URL!)
What happens:

User visits app after upgrade
Browser sees exact same URL
Browser: "I have this file cached" → uses OLD Splunk 8.2 version
❌ User still runs Splunk 8.2 JavaScript on Splunk 9.0 backend
The Problems This Causes:

// Splunk 9.0 i18n.js (on server, but NOT loaded)
i18n.newSplunk9Feature = function() { ... }

// Splunk 8.2 i18n.js (cached in browser, STILL RUNNING)
// Missing: newSplunk9Feature

// Your app tries to call:
i18n.newSplunk9Feature();
// ❌ TypeError: i18n.newSplunk9Feature is not a function
Real-World Impact:
Broken Functionality

New Splunk 9.0 features don't work
API calls fail (backend expects 9.0 format, JS sends 8.2 format)
UI Rendering Issues


<!-- Splunk 9.0 HTML expects new JS classes -->
<div class="splunk-9-new-component"></div>

<!-- But cached 8.2 JS doesn't know how to render it -->
Silent Failures

Errors in browser console
Features appear "broken"
User thinks upgrade failed
How Long Does Cache Persist?
Depends on cache headers. If Splunk set:


Cache-Control: max-age=31536000  (1 year!)
Without hash change, browser will not check for updates for up to 1 year! User would need to:

Hard refresh (Ctrl+F5)
Clear browser cache manually
Wait for cache expiration

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Valid observation. The hash-based URLs (e.g. @4D5115C2....83/js/i18n.js) were generated dynamically by Splunk's make_url() at render time via CherryPy/Mako — we were just a pass-through. Reproducing that mechanism without a runtime isn't feasible: the hash is computed by Splunk at startup from its own file contents, and we don't have access to it at ucc-gen build time.

The two endpoints with ?autoload=1 (config and i18ncatalog) are inherently dynamic and session-scoped, so they aren't aggressively cached by browsers regardless — the cache busting concern doesn't apply to them.

For i18n.js specifically, the actual cache behavior depends on what Cache-Control headers Splunk sets for unhashed static paths — which we haven't verified. We plan to check this against a running Splunk instance using run_splunk.sh and will follow up with results. If the headers turn out to be permissive, we'll document this as a known limitation of removing the Mako runtime dependency.

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.

What if ucc-gen build added some random hash? Or SHA of the js file? This way the hash would be different after TA upgrade.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch — I verified that /static/js/i18n.js is served with Cache-Control: public, max-age=31536000, so the concern from the earlier comment was valid.

Why a random hash or SHA won't work here:

  • Random hash: would change on every ucc-gen build, busting the cache on every TA upgrade. But i18n.js is a Splunk file — its content only changes when Splunk itself upgrades. Busting on every TA build would be the wrong signal.
  • SHA of the file: i18n.js is dynamically generated per-locale by Splunk's CherryPy at request time (see dispatch_i18n_js() in Splunk's i18n.py). We don't have access to its final content at ucc-gen build time, so we can't compute a meaningful SHA.

What we did instead:

config?autoload=1 (already loaded synchronously in <head>) populates window.$C, which includes BUILD_NUMBER — a value that changes on every Splunk upgrade. We use it to build the URL dynamically at page load:

var _b = window.$C && window.$C.BUILD_NUMBER ? '/@' + window.$C.BUILD_NUMBER : '';
_loadScript('../../static' + _b + '/js/i18n.js')

This produces URLs like ../../static/@389585/js/i18n.js. Splunk's customstaticdir.py strips any /@ANYTHING segment before serving the file, so the path resolves correctly regardless of the value. The cache is busted exactly when Splunk upgrades — which is when i18n.js content actually changes.

@wtobis-splunk wtobis-splunk force-pushed the feat/remove-mako-and-cherrypy branch from 149e136 to 7a0a17a Compare March 24, 2026 22:07
@wtobis-splunk wtobis-splunk force-pushed the feat/remove-mako-and-cherrypy branch from 5151d97 to fd60793 Compare March 27, 2026 18:22
@github-actions
Copy link
Copy Markdown

Code Coverage 🎉

Type PR Develop Change Status
Line Coverage 94.24% 94.23% 0.01% 🟢 Increased
Branch Coverage 90.50% 90.50% 0.00% ⚪ Unchanged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants