Skip to content
Merged
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
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ jobs:
run: pnpm build

- name: Test
run: pnpm -r test --if-present
# `--if-present` must precede the script name, otherwise pnpm forwards it
# to the script (`objectstack build --if-present` → "Nonexistent flag").
run: pnpm -r --if-present test

smoke:
name: Smoke (todo dev server)
Expand Down
69 changes: 50 additions & 19 deletions packages/all/scripts/compile-marketplace.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@
// and the CLI's serve path validates with `ObjectStackDefinitionSchema` (schema
// only), so the single-app / namespace-prefix gates correctly do not apply.

import {
readFileSync,
writeFileSync,
mkdirSync,
readdirSync,
existsSync,
} from 'node:fs';
import { readFileSync, writeFileSync, mkdirSync, readdirSync, existsSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

Expand Down Expand Up @@ -70,11 +64,32 @@ const safeFilename = (manifestId) => `${manifestId.replace(/[^a-zA-Z0-9._-]/g, '
// Arrays concatenated at the environment layer (mirrors `composeStacks`'
// CONCAT_ARRAY_FIELDS, minus the singletons we de-dupe below).
const CONCAT_FIELDS = [
'translations', 'objectExtensions', 'objects', 'apps', 'views', 'pages',
'dashboards', 'reports', 'actions', 'themes', 'flows', 'jobs',
'emailTemplates', 'sharingRules', 'policies', 'apis', 'webhooks', 'agents',
'skills', 'hooks', 'mappings', 'analyticsCubes', 'connectors', 'datasources',
'portals', 'data',
'translations',
'objectExtensions',
'objects',
'apps',
'views',
'pages',
'dashboards',
'reports',
'actions',
'themes',
'flows',
'jobs',
'emailTemplates',
'sharingRules',
'policies',
'apis',
'webhooks',
'agents',
'skills',
'hooks',
'mappings',
'analyticsCubes',
'connectors',
'datasources',
'portals',
'data',
];

// Environment-level singletons keyed by `name`. Two installed apps can each ship
Expand Down Expand Up @@ -126,7 +141,9 @@ function installFromWorkspace() {
function readStore(dir) {
if (!existsSync(dir)) return [];
const out = [];
for (const file of readdirSync(dir).filter((f) => f.endsWith('.json')).sort()) {
for (const file of readdirSync(dir)
.filter((f) => f.endsWith('.json'))
.sort()) {
let entry;
try {
entry = JSON.parse(readFileSync(join(dir, file), 'utf8'));
Expand All @@ -137,7 +154,8 @@ function readStore(dir) {
// Accept either the runtime wrapper ({ manifest: <artifact> }) or a bare
// artifact dropped straight into the folder.
const artifact = entry?.manifest?.objects || entry?.manifest?.apps ? entry.manifest : entry;
const source = artifact?.manifest?.namespace || entry?.manifestId || file.replace(/\.json$/, '');
const source =
artifact?.manifest?.namespace || entry?.manifestId || file.replace(/\.json$/, '');
out.push({ source, artifact });
}
return out;
Expand All @@ -148,8 +166,12 @@ function readInstalledArtifacts() {
const cache = readStore(INSTALLED_DIR);
const live = readStore(LIVE_INSTALL_DIR);
if (live.length > 0) {
log(` ⓘ folding in ${live.length} live marketplace install(s) from .objectstack/installed-packages/`);
log(' (the runtime rehydrates that folder too — run `start` from a clean cwd to avoid double-load)');
log(
` ⓘ folding in ${live.length} live marketplace install(s) from .objectstack/installed-packages/`,
);
log(
' (the runtime rehydrates that folder too — run `start` from a clean cwd to avoid double-load)',
);
}
// De-dupe by namespace; cache wins (it's the deterministic workspace copy).
const seen = new Set(cache.map((e) => e.source));
Expand Down Expand Up @@ -194,7 +216,10 @@ function compile(store) {
for (const field of DEDUP_BY_NAME) {
for (const item of artifact[field] ?? []) {
if (!dedup[field].has(item.name)) dedup[field].set(item.name, item);
else log(` ! ${field.slice(0, -1)} '${item.name}' from '${source}' shadowed (already installed)`);
else
log(
` ! ${field.slice(0, -1)} '${item.name}' from '${source}' shadowed (already installed)`,
);
}
}

Expand All @@ -213,7 +238,11 @@ function compile(store) {
if (requires.size > 0) env.requires = [...requires];

supportedLocales.add(defaultLocale);
env.i18n = { defaultLocale, supportedLocales: [...supportedLocales], fallbackLocale: defaultLocale };
env.i18n = {
defaultLocale,
supportedLocales: [...supportedLocales],
fallbackLocale: defaultLocale,
};

return env;
}
Expand All @@ -237,7 +266,9 @@ mkdirSync(dirname(OUT), { recursive: true });
writeFileSync(OUT, `${JSON.stringify(env, null, 2)}\n`);

log('');
log(`✓ Composed ${store.length} apps · ${env.objects?.length ?? 0} objects · ${env.flows?.length ?? 0} flows`);
log(
`✓ Composed ${store.length} apps · ${env.objects?.length ?? 0} objects · ${env.flows?.length ?? 0} flows`,
);
log(` apps: ${(env.apps ?? []).map((a) => a.name).join(', ')}`);
log(` installed-packages: ${INSTALLED_DIR.replace(`${PACKAGES_DIR}/`, '')}`);
log(` → ${OUT.replace(`${PACKAGES_DIR}/`, '')}`);
Expand Down
8 changes: 6 additions & 2 deletions packages/compliance/objectstack.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
"iconUrl": "https://cdn.objectos.app/icons/compliance.svg",
"homepageUrl": "https://github.com/objectstack-ai/templates/tree/main/packages/compliance",
"tags": ["compliance", "audit", "evidence", "soc2", "iso27001"],
"skills": ["objectstack-platform", "objectstack-data", "objectstack-ui", "objectstack-automation"],
"skills": [
"objectstack-platform",
"objectstack-data",
"objectstack-ui",
"objectstack-automation"
],
"readmePath": "README.md",
"translations": {
"zh-CN": {
Expand All @@ -23,4 +28,3 @@
}
}
}

32 changes: 28 additions & 4 deletions packages/compliance/src/apps/compliance.app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,33 @@ export const ComplianceApp = App.create({
label: 'Control Posture',
icon: 'gauge',
},
{ id: 'nav_framework', type: 'object', objectName: 'compliance_framework', label: 'Frameworks', icon: 'shield-check' },
{ id: 'nav_control', type: 'object', objectName: 'compliance_control', label: 'Controls', icon: 'shield' },
{ id: 'nav_evidence', type: 'object', objectName: 'compliance_evidence', label: 'Evidence', icon: 'paperclip' },
{ id: 'nav_assessment', type: 'object', objectName: 'compliance_assessment', label: 'Assessments', icon: 'clipboard-check' },
{
id: 'nav_framework',
type: 'object',
objectName: 'compliance_framework',
label: 'Frameworks',
icon: 'shield-check',
},
{
id: 'nav_control',
type: 'object',
objectName: 'compliance_control',
label: 'Controls',
icon: 'shield',
},
{
id: 'nav_evidence',
type: 'object',
objectName: 'compliance_evidence',
label: 'Evidence',
icon: 'paperclip',
},
{
id: 'nav_assessment',
type: 'object',
objectName: 'compliance_assessment',
label: 'Assessments',
icon: 'clipboard-check',
},
],
});
15 changes: 11 additions & 4 deletions packages/compliance/src/dashboards/control_posture.dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ import type { Dashboard } from '@objectstack/spec/ui';
export const ControlPostureDashboard: Dashboard = {
name: 'control_posture_dashboard',
label: 'Control Posture',
description:
'Pass rate, failing controls, expiring evidence, and in-flight assessments.',
description: 'Pass rate, failing controls, expiring evidence, and in-flight assessments.',

columns: 12,
gap: 4,
Expand All @@ -30,7 +29,12 @@ export const ControlPostureDashboard: Dashboard = {
showTitle: true,
showDescription: true,
actions: [
{ label: 'New Assessment', icon: 'Plus', actionType: 'modal', actionUrl: 'create_assessment' },
{
label: 'New Assessment',
icon: 'Plus',
actionType: 'modal',
actionUrl: 'create_assessment',
},
],
},

Expand Down Expand Up @@ -93,7 +97,10 @@ export const ControlPostureDashboard: Dashboard = {
options: {
columns: ['code', 'title', 'framework', 'criticality', 'last_assessed_at'],
pageSize: 10,
sort: [{ field: 'criticality', order: 'asc' }, { field: 'code', order: 'asc' }],
sort: [
{ field: 'criticality', order: 'asc' },
{ field: 'code', order: 'asc' },
],
},
},
{
Expand Down
Loading
Loading