sfcc-isml-development — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sfcc-isml-development (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill is SFRA-only. It intentionally avoids SiteGenesis patterns.
SFRA storefront markup is built around Bootstrap 4 (grid, forms, alerts, utilities). Keep your ISML consistent with existing SFRA markup and CSS conventions.
templates/default/** in an SFRA cartridge.common/layout/page / common/layout/checkout).<isinclude> and Bootstrap 4 markup.[ ] No business logic in ISML (no data fetches, no persistence)
[ ] <isscript> used only for SFRA asset registration (CSS/JS)
[ ] Output encoding is NOT disabled unless justified and safe
[ ] <iscontent>/<isredirect>/<iscache> placement constraints respected
[ ] Remote includes used sparingly with security middleware
[ ] Template receives all data via pdict (controller owns data)
[ ] Markup uses Bootstrap 4 classes (grid, forms, alerts)/my-cartridge/cartridge/templates/
/default # Default templates (SFRA)
/product/detail.isml
/util/modules.isml # Optional: <ismodule> tag definitions
/fr_FR # Locale overrides (use sparingly)NEVER use `<isscript>` for business logic. The only exception is asset management:
<!-- ✅ Only acceptable use of isscript -->
<isscript>
var assets = require('*/cartridge/scripts/assets.js');
assets.addCss('/css/product.css');
assets.addJs('/js/product.js');
</isscript>All data comes from controllers via pdict:
<!-- ✅ Correct: Data from controller -->
<div class="price h5 mb-0">${pdict.product.price.sales.formatted}</div>Use these classes/patterns by default:
| Goal | Bootstrap 4 pattern |
|---|---|
| Layout | container → row → col-* |
| Spacing | mt-*, mb-*, py-*, px-* |
| Buttons | btn btn-primary, btn btn-outline-primary |
| Alerts | alert alert-danger, alert alert-success |
| Forms | form-group, form-control, is-invalid, invalid-feedback |
| Responsive show/hide | d-none d-md-block, d-md-none |
Avoid mixing Bootstrap 5-only classes (e.g. g-*, row-cols-*, btn-close, badge bg-*) into SFRA baseline templates.
<isif condition="${pdict.product.available}">
<span class="badge badge-success">${Resource.msg('label.instock','product',null)}</span>
<iselseif condition="${pdict.product.preorderable}">
<span class="badge badge-info">${Resource.msg('label.preorder','product',null)}</span>
<iselse>
<span class="badge badge-secondary">${Resource.msg('label.outofstock','product',null)}</span>
</isif><isloop items="${products}" var="product" status="loopstate">
<div class="col-6 col-sm-4 col-lg-3 mb-3">
<div class="card h-100">
<div class="card-body">
<div class="small text-muted">#${loopstate.count}</div>
<div class="font-weight-bold">${product.name}</div>
</div>
<isif condition="${loopstate.first}">
<div class="card-footer bg-transparent">
<span class="badge badge-warning">${Resource.msg('label.featured','common',null)}</span>
</div>
</isif>
</div>
</div>
</isloop>Loop status: count (1-based), index (0-based), first, last, odd, even
<isset name="productName" value="${product.name}" scope="page"/>
<span>${productName}</span>
<isremove name="productName" scope="page"/>Scopes (required): page, request, session, pdict
<!-- HTML encoded (default) -->
<isprint value="${product.name}"/>
<!-- Unencoded (use carefully) -->
<isprint value="${htmlContent}" encoding="off"/>
<!-- Formatted -->
<isprint value="${price}" style="CURRENCY"/>
<isprint value="${order.creationDate}" style="DATE_SHORT"/><!-- Local include (shared pdict) -->
<isinclude template="product/components/price"/>
<!-- Remote include (isolated, own cache) -->
<isinclude url="${URLUtils.url('Product-GetPrice', 'pid', product.ID)}"/>Prefer local includes for components. Only use remote includes when you need an independent cache policy or request isolation; see the remote include reference.
Decorator template (common/layout/page.isml):
<!DOCTYPE html>
<html>
<head><title>${pdict.pageTitle}</title></head>
<body>
<isinclude template="components/header"/>
<main>
<isreplace/> <!-- Content inserted here -->
</main>
<isinclude template="components/footer"/>
</body>
</html>Using decorator:
<isdecorate template="common/layout/page">
<div class="content">
<h1>${pdict.welcomeMessage}</h1>
</div>
</isdecorate>SFRA provides two primary decorators:
common/layout/page - Standard storefront pagescommon/layout/checkout - Checkout process pagesUse <isdecorate> on almost all storefront templates; keep full <html>/<head>/<body> only in layout templates.
| Tag | Constraint |
|---|---|
<iscontent> | Must be before DOCTYPE |
<isredirect> | Must be before DOCTYPE |
<iscache> | Place at beginning |
<isreplace/> | Only inside decorator templates |
<isbreak>/<iscontinue>/<isnext> | Only inside <isloop> |
<!-- Cache for 24 hours -->
<iscache type="relative" hour="24"/>
<!-- Daily cache (expires at midnight) -->
<iscache type="daily" hour="0" minute="0"/>
<!-- Vary by price/promotion -->
<iscache type="relative" hour="1" varyby="price_promotion"/>Place <iscache> at the beginning of the template.
Prefer controller caching middleware (SFRA */cartridge/scripts/middleware/cache) for page-level caching decisions; use <iscache> selectively for fragments.
<!-- Must be first in template -->
<iscontent type="text/html" charset="UTF-8"/>
<!-- For JSON -->
<iscontent type="application/json" charset="UTF-8"/>Define in `util/modules.isml`:
<ismodule template="components/productcard"
name="productcard"
attribute="product"
attribute="showPrice"/>Use anywhere:
<isinclude template="util/modules"/>
<isproductcard product="${product}" showPrice="${true}"/>In SFRA, most reuse is done via <isinclude template="...">. Use <ismodule> custom tags only when it measurably improves readability/consistency.
Always rely on default encoding. <isprint> automatically HTML-encodes:
<!-- ✅ Secure (default) -->
<isprint value="${pdict.searchPhrase}" />
<!-- ❌ Vulnerable -->
<isprint value="${pdict.searchPhrase}" encoding="off" />For JavaScript context, use SecureEncoder:
<script>
var term = "${require('dw/util/SecureEncoder').forJavaScript(pdict.searchPhrase)}";
</script>For HTML attributes, prefer SecureEncoder.forHTMLAttribute(...). Avoid encoding="off" unless the value is fully controlled and intentionally contains HTML.
Pre-imported, use directly:
<!-- URLUtils -->
<a href="${URLUtils.url('Product-Show', 'pid', product.ID)}">View</a>
<img src="${URLUtils.staticURL('/images/logo.png')}" alt="Logo"/>
<!-- Resource (localization) -->
${Resource.msg('button.addtocart', 'product', null)}
${Resource.msgf('cart.items', 'cart', null, cartCount)}
<!-- StringUtils -->
${StringUtils.truncate(description, 100, '...')}<!-- Property access -->
${pdict.product.name}
${pdict.product.price.sales.value}
<!-- Method calls -->
${product.getAvailabilityModel().isInStock()}
<!-- Operators -->
${price > 100 ? 'expensive' : 'affordable'}
${firstName + ' ' + lastName}<!-- HTML comment (visible in source) -->
<iscomment>
ISML comment - stripped from output.
Use for sensitive documentation.
</iscomment><isdecorate> with SFRA layouts (common/layout/page, common/layout/checkout)<isinclude template> for component composition; keep components smallSecureEncoder for JS/attribute contextsserver.middleware.include + explicit security + cache policy<iscache> thoughtfully<form action="${URLUtils.url('Account-Login')}" method="post" class="login">
<input type="hidden" name="${pdict.csrf.tokenName}" value="${pdict.csrf.token}"/>
<div class="form-group">
<label class="form-control-label" for="login-email">
${Resource.msg('label.login.email','login',null)}
</label>
<input
id="login-email"
type="email"
class="form-control <isif condition="${pdict.loginForm.username.invalid}">is-invalid</isif>"
name="${pdict.loginForm.username.htmlName}"
value="${pdict.loginForm.username.value}"
autocomplete="email"
required>
<isif condition="${pdict.loginForm.username.invalid}">
<div class="invalid-feedback">
<isprint value="${pdict.loginForm.username.error}"/>
</div>
</isif>
</div>
<button type="submit" class="btn btn-primary btn-block">
${Resource.msg('button.login','login',null)}
</button>
</form>search_isml_elements("loop") // Find by intent
get_isml_element("isprint") // Full documentation
list_isml_elements() // All elements by categoryResource.msg(), parameterized messages, locale fallback, and internationalization best practices. Always use resource bundles instead of hardcoded text in templates.<isreplace/>~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.