Skip to content
Open
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
5 changes: 5 additions & 0 deletions .codegraph/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# CodeGraph data files — local to each machine, not for committing.
# Ignore everything in .codegraph/ except this file itself, so transient
# files (the database, daemon.pid, sockets, logs) never show up in git.
*
!.gitignore
43 changes: 43 additions & 0 deletions 0001-fix-anolisa-add-missing-Provides-anolisa-component-n.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
From d8cbf695716fe68fa688a88ecb675577322e4d4b Mon Sep 17 00:00:00 2001
From: zhangtaibo <zhangtaibo.ztb@alibaba-inc.com>
Date: Fri, 14 Aug 2026 19:11:46 +0800
Subject: [PATCH] fix(anolisa): add missing Provides: anolisa-component(<name>)
to os-skills, tokenless, ws-ckpt, agent-sec-core spec files

Four RPM spec files were missing the 'Provides: anolisa-component(<name>)'
virtual provide line that agentsight, copilot-shell, cosh-ng, and skillfs
already declare. When the repo-side components-v2.toml is unavailable
(HTTP 404) and no package_map entry exists in repo.toml, the ANOLISA RPM
resolver falls through all three resolution paths and returns empty
candidates, causing 'INVALID_ARGUMENT: not an ANOLISA RPM component'.

Fixes #2559 (same root cause, covers os-skills/tokenless/ws-ckpt/sec-core).
Complements PR #2560 (agent-memory spec).

Verified on ECS: with this patch, rpm-build.sh produces RPMs that include
the anolisa-component provides, and 'anolisa adapter scan' correctly lists
the component adapters after install+adopt.
---
src/agent-sec-core/agent-sec-core.spec.in | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/src/agent-sec-core/agent-sec-core.spec.in b/src/agent-sec-core/agent-sec-core.spec.in
index 80a7db31..0e676fb5 100644
--- a/src/agent-sec-core/agent-sec-core.spec.in
+++ b/src/agent-sec-core/agent-sec-core.spec.in
@@ -61,6 +61,12 @@ Requires: agent-sec-hermes-hook = %{version}-%{release}
Requires: agent-sec-qwen-code-hook = %{version}-%{release}
Requires: agent-sec-skills = %{version}-%{release}

+# Declare ANOLISA component identity so that `anolisa install sec-core --backend rpm`
+# can resolve this package via RPM Provides when the repo-side components-v2.toml
+# is unavailable (404) and no package_map entry exists — the resolver falls through to
+# RPM Provides but finds no anolisa-component(sec-core) capability.
+Provides: anolisa-component(sec-core)
+
%description
Agent-Sec-Core is an OS-level security baseline and hardening framework for AI Agents.
This metapackage installs all agent-sec-core components including CLI, hooks, and skills.
--
2.43.7

1 change: 0 additions & 1 deletion src/anolisa/crates/anolisa-cli/src/repo_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,6 @@ pub fn raw_index_v2_url(base_url: &str) -> String {
///
/// Released clients continue reading this path, so publishers must preserve its
/// schema v1 contents when publishing later component-index generations.
#[cfg(test)]
pub fn component_index_url(base_url: &str) -> String {
format!("{}/components.toml", raw_root(base_url))
}
Expand Down
51 changes: 43 additions & 8 deletions src/anolisa/crates/anolisa-cli/src/resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use anolisa_platform::pkg_query::{PackageQuery, PackageQueryError};
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::repo_config::{BackendConfig, HostVars, RepoConfig, component_index_v2_url};
use crate::repo_config::{BackendConfig, HostVars, RepoConfig, component_index_url, component_index_v2_url};

/// On-disk schema version for repo-side `components-v2.toml`.
pub(crate) const COMPONENT_INDEX_SCHEMA_VERSION: u32 = 2;
Expand Down Expand Up @@ -54,6 +54,7 @@ pub(crate) struct ComponentIndexEntry {
#[serde(default)]
pub(crate) summary: Option<String>,
/// Supported host OS/architecture combinations.
#[serde(default)]
pub(crate) targets: Vec<ComponentTarget>,
/// Backend-native package names for this component.
///
Expand Down Expand Up @@ -473,7 +474,11 @@ impl ComponentIndex {
}

fn validate(&self) -> Result<(), ComponentIndexError> {
if self.schema_version != COMPONENT_INDEX_SCHEMA_VERSION {
// Accept schema v1 and v2: v1 rows simply lack `targets`, which
// defaults to an empty vec via `#[serde(default)]`. This lets the
// v2 parser gracefully load v1 `components.toml` when the v2 file
// has not been published to the mirror yet.
if !matches!(self.schema_version, 1 | 2) {
return Err(ComponentIndexError::UnsupportedSchema {
actual: self.schema_version,
expected: COMPONENT_INDEX_SCHEMA_VERSION,
Expand All @@ -492,7 +497,9 @@ impl ComponentIndex {
reason: format!("duplicate component '{name}'"),
});
}
if entry.targets.is_empty() {
// v1 indexes predate the `targets` field; skip the non-empty
// check for schema v1 (targets defaults to empty via serde).
if self.schema_version >= 2 && entry.targets.is_empty() {
return Err(ComponentIndexError::Invalid {
reason: format!("component '{name}' must declare at least one target"),
});
Expand Down Expand Up @@ -741,18 +748,43 @@ pub(crate) fn load_component_index(
let url = component_index_v2_url(&base_url);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P1] v1/v2 回退逻辑忽略非 404 场景

load_component_index 中对 v2 components-v2.toml 的 fetch 仅在 reason.contains("http status 404") 时回退到 v1,否则直接返回原始 ComponentIndexError::Fetch。这会让如超时、DNS 失败、403 等非 404 错误在 v1 也可用时依然导致命令整体失败,违背“镜像暂未部署 v2 时尽量保持可用”的目标。建议将回退条件扩展为“任何 v2 fetch 失败但 v1 fetch 成功都接受 v1”,并在错误信息中区分“v1 也失败”与“v1 成功”。

(位置:src/anolisa/crates/anolisa-cli/src/resolution.rs:748-768)


🤖 Generated by QoderFix in Qoder


let cache = DownloadCache::new(layout.cache_dir.clone());
let downloaded = match fetch_index_url(&cache, &url) {
Ok(art) => art,
Err(ComponentIndexError::Fetch { ref reason })
if reason.contains("http status 404") =>
{
// v2 not published yet — fall back to v1 components.toml.
// The v2 parser accepts v1 rows because `targets` has
// `#[serde(default)]`, so legacy indexes without targets
// still load (components simply appear as "no target info").
let v1_url = component_index_url(&base_url);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore target support when falling back to v1

When the mirror has not published components-v2.toml, this 404 path loads schema-version-1 components.toml; those files declare platforms, not targets, while this patch defaults missing targets to an empty vec and skips the non-empty validation. Downstream ComponentIndexEntry::supports_target() only checks targets, so every fallback-loaded component is treated as unsupported: anolisa list marks them unavailable and install --all filters them all out. Please translate the v1 platform data or otherwise preserve legacy target semantics before returning the fallback index.

Useful? React with 👍 / 👎.

fetch_index_url(&cache, &v1_url).map_err(|err| ComponentIndexError::Fetch {
reason: format!(
"failed to fetch component index (tried v2 then v1): {err}"
),
})?
}
Err(err) => return Err(err),
};
ComponentIndex::load(&downloaded.cached_path)
}

/// Fetch a component index TOML from `url` into `cache`.
fn fetch_index_url(
cache: &DownloadCache,
url: &str,
) -> Result<anolisa_core::download::DownloadedArtifact, ComponentIndexError> {
#[cfg(test)]
if !url.starts_with("file://") {
return Err(ComponentIndexError::Fetch {
reason: format!("test mode: refusing non-file URL {url}"),
});
}
let downloaded = cache
.fetch(&url, None)
cache
.fetch(url, None)
.map_err(|err| ComponentIndexError::Fetch {
reason: format!("failed to fetch {url}: {err}"),
})?;
ComponentIndex::load(&downloaded.cached_path)
})
}

/// Best-effort load of repo-side `components-v2.toml`.
Expand Down Expand Up @@ -1325,7 +1357,10 @@ cosh = "site-copilot"

#[test]
fn unsupported_schema_is_rejected() {
Comment on lines 1357 to 1359

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P2] v1/v2 schema 接受范围与测试略有不一致

ComponentIndex::validate 改为接受 schema_version 为 1 或 2,但单元测试 unsupported_schema_is_rejected 只对值 99 进行校验,未显式覆盖 v1/v2 正常路径,也未防止未来误改为只接受 2。为避免回归,建议增加覆盖:断言 1 和 2 均通过、其它值(如 0、3、99)被拒绝。

(位置:src/anolisa/crates/anolisa-cli/src/resolution.rs:473-483, 1357-1364)


🤖 Generated by QoderFix in Qoder

for actual in [1, 99] {
// Schema v1 and v2 are accepted; anything else is rejected.
// v1 is accepted because `targets` defaults to an empty vec and
// the non-empty-target check is skipped for schema v1.
for actual in [99] {
let source = format!("schema_version = {actual}");
let err = ComponentIndex::from_toml_str(&source, "components.toml")
.expect_err("unsupported schema");
Expand Down
Loading