Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/.vuepress/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import CodeTabs from "./components/CodeTabs.vue";
import TableTabs from "./components/TableTabs.vue";
import ELSTechnology from "./components/ELSTechnology.vue";
import ELSRTechnology from "./components/ELSRTechnology.vue";
import SecureChainTechnology from "./components/SecureChainTechnology.vue";
import ELSOSSelector from "./components/ELSOSSelector.vue";
import ELSPrerequisites from "./components/ELSPrerequisites.vue";
import ELSSteps from "./components/ELSSteps.vue";
Expand Down Expand Up @@ -55,6 +56,7 @@ export default defineClientConfig({
app.component("TableTabs", TableTabs);
app.component("ELSTechnology", ELSTechnology);
app.component("ELSRTechnology", ELSRTechnology);
app.component("SecureChainTechnology", SecureChainTechnology);
app.component("ELSOSSelector", ELSOSSelector);
app.component("ELSPrerequisites", ELSPrerequisites);
app.component("ELSSteps", ELSSteps);
Expand Down
339 changes: 339 additions & 0 deletions docs/.vuepress/components/SecureChainTechnology.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
<template>
<div class="heading text-center">
<h2>Get your open-source packages – verified, malware-free, and secured for as long as they're in your stack.</h2>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Drop "malware-free." We deliver verified, signed, rebuilt artifacts — that's a defensible, specific claim. "Malware-free" is a stronger guarantee than the product actually makes and creates needless legal/support exposure if a downstream dependency is later found to contain malicious code.

Suggest:

<h2>Get your open-source packages — verified, signed, and supported for as long as they're in your stack.</h2>

(Same wording as the per-product page intro on lodash/README.md.)

</div>

<div class="supported-product-sorting">
<input
v-model="search"
type="text"
placeholder="Search for a Technology"
class="search-box"
/>

<div class="sp-sort-head">
<ul>
<li class="head-ecosystem">Ecosystem</li>
<li class="head-product">Product</li>
<li class="head-versions">Versions</li>
</ul>
</div>

<div class="sp-sort-body">
<div class="ecosystem-tabs">
<ul>
<li
v-for="(item, index) in filteredData"
:key="index"
:class="{ active: activeTab === index }"
@click="activeTab = index"
>
<img :src="item.ecosystemIcon" class="ecosystem-icon" alt="" aria-hidden="true" />
{{ item.ecosystem }}
</li>
</ul>
</div>

<div class="sp-sort-row" v-if="filteredData[activeTab]">
<div class="scroll-container">
<ul class="project-list">
<li
v-for="(project, pIndex) in getFilteredProjects(filteredData[activeTab])"
:key="pIndex"
>
<a
v-if="project.link"
:href="getProjectHref(project)"
class="project-row clickable"
>
<span class="project-name">{{ project.name }}</span>
<span class="project-versions">
<span v-if="project.detailsHash">
versions vary per module
</span>
<span v-else>{{ project.versions }}</span>
</span>
<span class="project-arrow">&rarr;</span>
</a>
<div v-else class="project-row">
<span class="project-name">{{ project.name }}</span>
<span class="project-versions">
<span v-if="project.detailsHash">
versions vary per module — details
</span>
<span v-else>{{ project.versions }}</span>
</span>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>

<script setup>
import { ref, computed } from "vue";

const search = ref("");
const activeTab = ref(0);

// add /images/rust.webp first — it does not yet exist in public/images.
const techData = [
{
ecosystem: "JavaScript",
ecosystemIcon: "/images/javascript.webp",
projects: [
{
name: "Lodash",
versions: "TBD",
link: "./lodash/",
},
],
},
/*
{
ecosystem: "Python",
ecosystemIcon: "/images/python.webp",
projects: [],
},
{
ecosystem: "Java",
ecosystemIcon: "/images/java.webp",
projects: [],
},
{
ecosystem: "Go",
ecosystemIcon: "/images/go_logo.webp",
projects: [],
},
{
ecosystem: "Rust",
ecosystemIcon: "/images/rust.webp", // TODO: add rust.webp before uncommenting
projects: [],
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remove the Rust block. There is no roadmap commitment for Rust SecureChain — leaving it in the source (even commented) signals intent to ship and tends to leak into screenshots, sales decks, and customer expectations. Trim the planned ecosystems to Python / Java / Go / PHP, which are the four we've been saying out loud.

{
ecosystem: "PHP",
ecosystemIcon: "/images/php-logo.webp",
projects: [],
},
*/
];

const filteredData = computed(() => {
const term = search.value.toLowerCase();
const result = techData
.map((item) => {
const matchEcosystem = item.ecosystem.toLowerCase().includes(term);
const filteredProjects = item.projects.filter((p) =>
p.name.toLowerCase().includes(term)
);
if (term && !matchEcosystem && filteredProjects.length === 0) return null;
return {
...item,
projects:
filteredProjects.length > 0 || matchEcosystem
? filteredProjects.length > 0
? filteredProjects
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mutating reactive state inside computed() is a Vue 3 antipattern (activeTab.value = 0 here triggers a reactivity warning in dev and can cause a re-render loop in edge cases). Move the reset into a watch(filteredData, ...) or watchEffect so the computed remains a pure getter.

: item.projects
: [],
};
})
.filter(Boolean);

if (activeTab.value >= result.length) activeTab.value = 0;

return result;
});

function getFilteredProjects(item) {
return item.projects;
}

function getProjectHref(project) {
if (project.detailsHash) {
return `${project.link}#${project.detailsHash}`;
}
return project.link;
}
</script>

<style scoped>
.supported-product-sorting {
border-radius: 23px;
border: 3px solid #D9EDFF;
box-shadow: 0px 4px 58px 0px rgba(53, 156, 243, 0.15);
padding: 30px;
padding: 1rem;
background-color: #fff;
}

.heading.text-center {
text-align: center;
margin-bottom: 1rem;
}

.search-box {
width: 50%;
padding: 0.4rem 1rem;
font-size: 1rem;
margin: 0 auto 1rem auto;
border-radius: 20px;
border: 1px solid #ccc;
display: block;
}

.sp-sort-head ul {
display: flex;
list-style: none;
padding: 0.3rem;
margin: 0 0 0.5rem 0;
font-weight: bold;
font-size: 1rem;
border-bottom: 1px solid #eee;
}

.sp-sort-head li {
text-align: left;
padding-left: 0.5rem;
}

.sp-sort-head .head-ecosystem {
flex: 0 0 33.333%;
}

.sp-sort-head .head-product {
flex: 0 0 29.7%;
}

.sp-sort-head .head-versions {
flex: 1;
}

.sp-sort-body {
display: flex;
gap: 0;
border-radius: 8px;
overflow: hidden;
}

.ecosystem-tabs {
width: 33.333%;
border-right: none;
}

.ecosystem-tabs ul {
list-style: none;
padding: 0;
margin: 0;
}

.ecosystem-tabs li {
display: flex;
align-items: center;
cursor: pointer;
background-color: #fff;
min-height: 2.5rem;
margin-bottom: 0.4rem;
border-bottom: none;
padding: 0.25rem 0.5rem;
border-radius: 6px;
transition: background-color 0.15s ease;
}

.ecosystem-tabs li:hover {
background-color: #f5f7fa;
}

.ecosystem-tabs li.active {
background-color: #FEF6F2;
color: #000;
font-weight: bold;
}

.ecosystem-icon {
height: auto;
width: 20px;
margin-right: 0.5rem;
}

.sp-sort-row {
width: 66%;
}

.scroll-container {
max-height: 300px;
overflow-y: auto;
width: auto;
}

.project-list {
list-style: none;
margin: 0;
background-color: #FEF6F2;
padding: 0.25rem 0.5rem;
}

.project-row {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.5rem 0.5rem;
border-bottom: 1px solid #f0d4c2;
transition: all 0.2s ease;
text-decoration: none;
color: inherit;
border-radius: 6px;
}

.project-row.clickable {
cursor: pointer;
}

a.project-row.clickable:hover {
background: #FEF6F2;
box-shadow: 0 2px 8px rgba(244, 130, 67, 0.1);
}

a.project-row.clickable:hover .project-arrow {
opacity: 1;
transform: translateX(0);
color: #F48243;
}

a.project-row.clickable:hover .project-name,
a.project-row.clickable:hover .project-versions {
color: #F48243;
}

.project-list > li:last-child .project-row {
border-bottom: none;
}

.project-name {
flex: 0 0 45%;
min-width: 0;
word-wrap: break-word;
font-size: 0.9rem;
font-weight: 500;
color: #1b1f27;
transition: color 0.2s ease;
}

.project-versions {
flex: 1;
font-size: 0.85rem;
line-height: 1.4;
word-wrap: break-word;
color: #5c6370;
}

.project-arrow {
font-size: 1.1rem;
opacity: 0;
transform: translateX(-4px);
transition: all 0.2s ease;
color: #5c6370;
flex-shrink: 0;
}
</style>
5 changes: 5 additions & 0 deletions docs/.vuepress/config-client/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export default [
description: "provides security fixes for open-source applications after official support ends.",
link: "/els-for-applications/",
},
{
title: "SecureChain for Open Source",
description: "delivers verified, malware-free open-source packages from a single trusted source - stopping threats at install, continuously patching vulnerabilities, and extending protection beyond end of life across Python, Java, JavaScript, Go, Rust, and PHP.",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Two issues in this description:

  1. "malware-free" — same as the H2 in the component, drop it. We do not make a no-malware guarantee; the verifiable claim is "verified, signed, rebuilt from trusted sources."
  2. "Python, Java, JavaScript, Go, Rust, and PHP" — only JavaScript ships at launch; Python is on hold; Java is in the AI pipeline; Rust isn't on the roadmap at all. Don't advertise six ecosystems on the home card.

Suggest:

description: "delivers verified, signed, continuously patched open-source packages from a trusted, TuxCare-managed registry — drop-in replacements that extend protection beyond upstream end of life. Available for JavaScript at launch, with Python, Java, Go, and PHP on the roadmap.",

link: "/securechain/",
},
{
title: "Subscription Management Portal",
description: "The TuxCare subscription management portal is designed to easily manage your licenses of TuxCare products and services by means of a user-friendly interface.",
Expand Down
Loading