package execenv import ( "encoding/json" "os" ) // Catalog 是管理员可编辑的白名单。不在白名单里的包不会自动安装。 type Catalog struct { MaxWheelBytes int64 `json:"maxWheelBytes"` Allow []CatalogEntry `json:"allow"` Deny []string `json:"deny"` } // CatalogEntry 的 Spec 为空表示任意版本;非空时是给人类看的范围说明, // 自动批准只看包名是否在列,版本冲突另由基础层锁判定。 type CatalogEntry struct { Name string `json:"name"` Spec string `json:"spec,omitempty"` Reason string `json:"reason,omitempty"` } // DefaultCatalog 是第一次创建环境根时落下的名单。之后以磁盘上的 catalog.json 为准。 func DefaultCatalog() Catalog { return Catalog{ MaxWheelBytes: 80 << 20, Allow: []CatalogEntry{ {Name: "python-docx", Reason: "Word 交付物"}, {Name: "openpyxl", Reason: "Excel"}, {Name: "python-pptx", Reason: "PPT"}, {Name: "lxml", Reason: "OOXML"}, {Name: "pillow", Reason: "图片"}, {Name: "numpy", Reason: "数值"}, {Name: "matplotlib", Reason: "图表"}, {Name: "pypdf", Reason: "PDF 读取"}, {Name: "reportlab", Reason: "PDF 生成"}, {Name: "markdown", Reason: "Markdown"}, {Name: "pdfplumber", Reason: "PDF 抽取"}, }, Deny: []string{"setuptools", "pip"}, } } func (r *Root) LoadCatalog() (Catalog, error) { raw, err := os.ReadFile(r.CatalogPath()) if err != nil { return Catalog{}, err } var c Catalog if err := json.Unmarshal(raw, &c); err != nil { return Catalog{}, err } if c.MaxWheelBytes <= 0 { c.MaxWheelBytes = 80 << 20 } return c, nil } func (c Catalog) allowed(name string) bool { n := normName(name) for _, e := range c.Allow { if normName(e.Name) == n { return true } } return false } func (c Catalog) denied(name string) bool { n := normName(name) for _, d := range c.Deny { if normName(d) == n { return true } } return false }