mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
* debrand: signoz/SigNoz/SIGNOZ -> o11y/O11y/O11Y across the tree Rename all SigNoz *branding* to O11y in file contents, file/dir names, package names, env vars, config keys, comments, docs, SDK code, and the ClickHouse schema identifiers the querier reads. Collector dependency: - Repoint github.com/hanzoai/signoz-otel-collector -> github.com/hanzoai/otel-collector and bump v0.144.6 -> v0.144.7 (go.mod + go.sum reconciled via go mod tidy). Internal package paths also debranded upstream: signozschemamigrator -> o11yschemamigrator, signozlogspipelineprocessor -> o11ylogspipelineprocessor. - Fix: v0.144.7 dropped otelconst.DistributedFieldKeysTable from the collector's public constants; pin FieldKeysTable = "distributed_field_keys" locally in pkg/telemetrymetadata/tables.go. Package/dir renames (package decl + all importers): pkg/apiserver/signozapiserver -> o11yapiserver, plus signozalertmanager, signozauthzapi, signozglobal, signozquerier, signozruler, and pkg/signoz -> pkg/o11y. Schema (read plane): signoz_traces/metrics/logs/metadata/analytics/meter and signoz_index_v3/index_v2/error_index_v2/spans (+ distributed_*) -> o11y_*. Data-preserving cutover migration added: deploy/clickhouse/migrations/0001_rename_signoz_to_o11y.sql (metadata-only RENAME DATABASE/TABLE, no drop/recreate). Preserved (attribution / external / wire contracts): - LICENSE + NOTICE verbatim (incl. "software from SigNoz", "Copyright ... SigNoz Inc."). - Upstream github.com/SigNoz/* repo URLs + @SigNoz/* CODEOWNERS teams. - Billing resource-attribute regex "signoz.workspace.*" (external wire contract). go build ./pkg/... ./cmd/... = 0; gofmt clean; renamed+schema pkg tests pass. * o11y: bump collector to v0.144.8 (o11y_* physical schema writer) + lockstep deploy plan Collector v0.144.8's schema-migrator + exporters now CREATE/WRITE the same o11y_* physical databases/tables the querier reads and the RENAME migration (0001_rename_signoz_to_o11y.sql) targets. Cross-checked byte-identical: writer DB set == migration target DB set (6); writer prefixed-table set == migration target table set (8); o11y querier reads and cloud reads are subsets of that set. Zero table-name mismatches between writer, readers, and migration. Collector go.mod unchanged between v0.144.7 and v0.144.8 (identical go.mod hash) — pure source rename, no module-graph change. Adds deploy/clickhouse/DEPLOY_signoz_to_o11y_cutover.md: the lockstep order (collector v0.144.8 -> RENAME migration -> o11y+cloud readers) with a fresh/scratch-ClickHouse pre-flight (create via migrator, emit trace+metric, query back) and rollback. Ships together or telemetry blackholes. go build ./pkg/... ./cmd/community = 0.
175 lines
4.8 KiB
JavaScript
175 lines
4.8 KiB
JavaScript
/**
|
|
* Rule: no-raw-absolute-path
|
|
*
|
|
* Catches patterns that break at runtime when the app is served from a
|
|
* sub-path (e.g. /o11y/):
|
|
*
|
|
* 1. window.open(path, '_blank')
|
|
* → use openInNewTab(path) which calls withBasePath internally
|
|
*
|
|
* 2. window.location.origin + path / `${window.location.origin}${path}`
|
|
* → use getAbsoluteUrl(path)
|
|
*
|
|
* 3. frontendBaseUrl: window.location.origin (bare origin usage)
|
|
* → use getBaseUrl() to include the base path
|
|
*
|
|
* 4. window.location.href = path
|
|
* → use withBasePath(path) or navigate() for internal navigation
|
|
*
|
|
* External URLs (first arg starts with "http") are explicitly allowed.
|
|
*/
|
|
|
|
function isOriginAccess(node) {
|
|
return (
|
|
node.type === 'MemberExpression' &&
|
|
!node.computed &&
|
|
node.property.name === 'origin' &&
|
|
node.object.type === 'MemberExpression' &&
|
|
!node.object.computed &&
|
|
node.object.property.name === 'location' &&
|
|
node.object.object.type === 'Identifier' &&
|
|
node.object.object.name === 'window'
|
|
);
|
|
}
|
|
|
|
function isHrefAccess(node) {
|
|
return (
|
|
node.type === 'MemberExpression' &&
|
|
!node.computed &&
|
|
node.property.name === 'href' &&
|
|
node.object.type === 'MemberExpression' &&
|
|
!node.object.computed &&
|
|
node.object.property.name === 'location' &&
|
|
node.object.object.type === 'Identifier' &&
|
|
node.object.object.name === 'window'
|
|
);
|
|
}
|
|
|
|
function isExternalUrl(node) {
|
|
if (node.type === 'Literal' && typeof node.value === 'string') {
|
|
return node.value.startsWith('http://') || node.value.startsWith('https://');
|
|
}
|
|
if (node.type === 'TemplateLiteral' && node.quasis.length > 0) {
|
|
const raw = node.quasis[0].value.raw;
|
|
return raw.startsWith('http://') || raw.startsWith('https://');
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// window.open(withBasePath(x)) and window.open(getAbsoluteUrl(x)) are already safe.
|
|
function isSafeHelperCall(node) {
|
|
return (
|
|
node.type === 'CallExpression' &&
|
|
node.callee.type === 'Identifier' &&
|
|
(node.callee.name === 'withBasePath' || node.callee.name === 'getAbsoluteUrl')
|
|
);
|
|
}
|
|
|
|
export default {
|
|
meta: {
|
|
type: 'suggestion',
|
|
docs: {
|
|
description:
|
|
'Disallow raw window.open and origin-concatenation patterns that miss the runtime base path',
|
|
category: 'Base Path Safety',
|
|
},
|
|
schema: [],
|
|
messages: {
|
|
windowOpen:
|
|
'Use openInNewTab(path) instead of window.open(path, "_blank") — openInNewTab prepends the base path automatically.',
|
|
originConcat:
|
|
'Use getAbsoluteUrl(path) instead of window.location.origin + path — getAbsoluteUrl prepends the base path automatically.',
|
|
originDirect:
|
|
'Use getBaseUrl() instead of window.location.origin — getBaseUrl includes the base path.',
|
|
hrefAssign:
|
|
'Use withBasePath(path) or navigate() instead of window.location.href = path — ensures the base path is included.',
|
|
},
|
|
},
|
|
|
|
create(context) {
|
|
return {
|
|
// window.open(path, ...) — allow only external first-arg URLs
|
|
CallExpression(node) {
|
|
const { callee, arguments: args } = node;
|
|
if (
|
|
callee.type !== 'MemberExpression' ||
|
|
callee.object.type !== 'Identifier' ||
|
|
callee.object.name !== 'window' ||
|
|
callee.property.name !== 'open'
|
|
) {
|
|
return;
|
|
}
|
|
if (args.length === 0) {
|
|
return;
|
|
}
|
|
if (isExternalUrl(args[0])) {
|
|
return;
|
|
}
|
|
if (isSafeHelperCall(args[0])) {
|
|
return;
|
|
}
|
|
|
|
context.report({ node, messageId: 'windowOpen' });
|
|
},
|
|
|
|
// window.location.origin + path
|
|
BinaryExpression(node) {
|
|
if (node.operator !== '+') {
|
|
return;
|
|
}
|
|
if (isOriginAccess(node.left) || isOriginAccess(node.right)) {
|
|
context.report({ node, messageId: 'originConcat' });
|
|
}
|
|
},
|
|
|
|
// `${window.location.origin}${path}`
|
|
TemplateLiteral(node) {
|
|
if (node.expressions.some(isOriginAccess)) {
|
|
context.report({ node, messageId: 'originConcat' });
|
|
}
|
|
},
|
|
|
|
// window.location.origin used directly (not in concatenation)
|
|
// Catches: frontendBaseUrl: window.location.origin
|
|
MemberExpression(node) {
|
|
if (!isOriginAccess(node)) {
|
|
return;
|
|
}
|
|
|
|
const parent = node.parent;
|
|
// Skip if parent is BinaryExpression with + (handled by BinaryExpression visitor)
|
|
if (parent.type === 'BinaryExpression' && parent.operator === '+') {
|
|
return;
|
|
}
|
|
// Skip if inside TemplateLiteral (handled by TemplateLiteral visitor)
|
|
if (parent.type === 'TemplateLiteral') {
|
|
return;
|
|
}
|
|
|
|
context.report({ node, messageId: 'originDirect' });
|
|
},
|
|
|
|
// window.location.href = path
|
|
AssignmentExpression(node) {
|
|
if (node.operator !== '=') {
|
|
return;
|
|
}
|
|
if (!isHrefAccess(node.left)) {
|
|
return;
|
|
}
|
|
|
|
// Allow external URLs
|
|
if (isExternalUrl(node.right)) {
|
|
return;
|
|
}
|
|
// Allow safe helper calls
|
|
if (isSafeHelperCall(node.right)) {
|
|
return;
|
|
}
|
|
|
|
context.report({ node, messageId: 'hrefAssign' });
|
|
},
|
|
};
|
|
},
|
|
};
|