diff --git a/apollo/proto/v1/BUILD.bazel b/apollo/proto/v1/BUILD.bazel new file mode 100644 index 0000000..75b73f5 --- /dev/null +++ b/apollo/proto/v1/BUILD.bazel @@ -0,0 +1,65 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@com_github_grpc_ecosystem_grpc_gateway_v2//protoc-gen-openapiv2:defs.bzl", "protoc_gen_openapiv2") +load("@openapi_tools_generator_bazel//:defs.bzl", "openapi_generator") + +proto_library( + name = "apollopb_proto", + srcs = [ + "advisory.proto", + "affected_product.proto", + "apollo.proto", + "build.proto", + "cve.proto", + "fix.proto", + "short_code.proto", + ], + visibility = ["//visibility:public"], + deps = [ + "@com_envoyproxy_protoc_gen_validate//validate:validate_proto", + "@com_google_protobuf//:timestamp_proto", + "@com_google_protobuf//:wrappers_proto", + "@go_googleapis//google/api:annotations_proto", + "@go_googleapis//google/api:httpbody_proto", + ], +) + +go_proto_library( + name = "apollopb_go_proto", + compilers = [ + "//:go_apiv2", + "//:go_grpc", + "//:go_validate", + "@com_github_grpc_ecosystem_grpc_gateway_v2//protoc-gen-grpc-gateway:go_gen_grpc_gateway", + ], + importpath = "peridot.resf.org/apollo/pb", + proto = ":apollopb_proto", + visibility = ["//visibility:public"], + deps = [ + "@com_envoyproxy_protoc_gen_validate//validate:validate_go_proto", + "@go_googleapis//google/api:annotations_go_proto", + "@go_googleapis//google/api:httpbody_go_proto", + ], +) + +go_library( + name = "pb", + embed = [":apollopb_go_proto"], + importpath = "peridot.resf.org/apollo/pb", + visibility = ["//visibility:public"], +) + +protoc_gen_openapiv2( + name = "openapi", + proto = ":apollopb_proto", + simple_operation_ids = True, + single_output = True, +) + +openapi_generator( + name = "client_typescript", + generator = "typescript-fetch", + spec = ":openapi", + visibility = ["//visibility:public"], +) diff --git a/apollo/proto/v1/advisory.proto b/apollo/proto/v1/advisory.proto new file mode 100644 index 0000000..7dc1a27 --- /dev/null +++ b/apollo/proto/v1/advisory.proto @@ -0,0 +1,112 @@ +syntax = "proto3"; + +package resf.apollo.v1; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; +import "apollo/proto/v1/cve.proto"; +import "apollo/proto/v1/fix.proto"; + +option go_package = "peridot.resf.org/apollo/pb;apollopb"; + +message RPMs { + repeated string nvras = 1; +} + +// Advisory +// +// Product advisory +message Advisory { + enum Type { + TYPE_UNKNOWN = 0; + TYPE_SECURITY = 1; + TYPE_BUGFIX = 2; + TYPE_ENHANCEMENT = 3; + } + + // Type + // + // Type of advisory + Type type = 1; + + // Short code + // + // Errata prefix or short code + // Example: RLBA, RLEA, RLSA + string short_code = 2; + + // Name + // + // Full errata name + // Example: RLBA-2021:0001, RLSA-2021:0002 + string name = 3; + + // Synopsis + // + // Short description of advisory + string synopsis = 4; + + enum Severity { + SEVERITY_UNKNOWN = 0; + SEVERITY_LOW = 1; + SEVERITY_MODERATE = 2; + SEVERITY_IMPORTANT = 3; + SEVERITY_CRITICAL = 4; + } + + // Severity + // + // Severity of advisory. Used only for security advisories + Severity severity = 5; + + // Topic + // + // Topic of advisory + // Example: An update for the go-toolset:rhel8 module is now available for Rocky Linux 8. + string topic = 6; + + // Description + // + // Description of advisory. Contains information about changes and package. + string description = 7; + + // Solution + // + // How to solve the advisory. Contains information about how to apply the advisory changes + google.protobuf.StringValue solution = 8; + + // Affected products + // + // A list of affected products + repeated string affected_products = 9; + + // Fixes + // + // A list of tickets from upstream bug trackers + repeated Fix fixes = 10; + + // CVEs + // + // A list of CVEs assigned to this advisory + repeated CVE cves = 11; + + // References + // + // General references used in this advisory + repeated string references = 12; + + // Published at + // + // Timestamp the advisory is published at + google.protobuf.Timestamp published_at = 13; + + // RPMs + // + // Affected RPMs + map rpms = 14; + + // Reboot suggested + // + // Whether a system reboot should be suggested after applying this advisory + bool reboot_suggested = 15; +} diff --git a/apollo/proto/v1/affected_product.proto b/apollo/proto/v1/affected_product.proto new file mode 100644 index 0000000..ca3458c --- /dev/null +++ b/apollo/proto/v1/affected_product.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; + +package resf.apollo.v1; + +import "google/protobuf/wrappers.proto"; + +option go_package = "peridot.resf.org/apollo/pb;apollopb"; + +message AffectedProduct { + int64 product_id = 1; + google.protobuf.StringValue cve_id = 2; + string version = 3; + + enum State { + STATE_UNKNOWN = 0; + // CVE only affects downstream + STATE_UNDER_INVESTIGATION_DOWNSTREAM = 1; + // CVE affecting upstream and a fix still hasn't been issued + STATE_UNDER_INVESTIGATION_UPSTREAM = 2; + // CVE has been fixed upstream + STATE_FIXED_UPSTREAM = 3; + // CVE has been fixed downstream + // At this stage the CVE can be included in errata + STATE_FIXED_DOWNSTREAM = 4; + // CVE will NOT be fixed upstream + STATE_WILL_NOT_FIX_UPSTREAM = 5; + // CVE will NOT be fixed downstream + // This will probably never happen with Core, but may happen for SIGs + STATE_WILL_NOT_FIX_DOWNSTREAM = 6; + // CVE is out of support scope + STATE_OUT_OF_SUPPORT_SCOPE = 7; + // CVE affects product and upstream is working on a fix + STATE_AFFECTED_UPSTREAM = 8; + // CVE affects product and a fix is being worked out + STATE_AFFECTED_DOWNSTREAM = 9; + } + State state = 4; + + string package = 5; + google.protobuf.StringValue advisory = 6; +} diff --git a/apollo/proto/v1/apollo.proto b/apollo/proto/v1/apollo.proto new file mode 100644 index 0000000..eee4c18 --- /dev/null +++ b/apollo/proto/v1/apollo.proto @@ -0,0 +1,167 @@ +syntax = "proto3"; + +package resf.apollo.v1; + +import "google/api/annotations.proto"; +import "google/api/httpbody.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; +import "validate/validate.proto"; +import "apollo/proto/v1/advisory.proto"; + +option go_package = "peridot.resf.org/apollo/pb;apollopb"; + +service ApolloService { + // ListAdvisories + // + // Return a list of advisories by given filters. + // No filters returns all advisories + // This method is paginated + rpc ListAdvisories (ListAdvisoriesRequest) returns (ListAdvisoriesResponse) { + option (google.api.http) = { + get: "/v2/advisories" + }; + } + + // ListAdvisoriesRSS + // + // Same as ListAdvisories but returns an RSS feed + // Only returns 25 latest advisories + // Supports filters + rpc ListAdvisoriesRSS (ListAdvisoriesRSSRequest) returns (google.api.HttpBody) { + option (google.api.http) = { + get: "/v2/advisories:rss" + }; + } + + // GetAdvisory + // + // Returns an advisory with given ID if found, else returns NotFound + rpc GetAdvisory (GetAdvisoryRequest) returns (GetAdvisoryResponse) { + option (google.api.http) = { + get: "/v2/advisories/{id=*}" + }; + } +} + +message AdvisoryFilters { + // Product + // + // The product to fetch advisories for + // For example: Rocky Linux 8 + google.protobuf.StringValue product = 1; + + // Before + // + // Advisories published before timestamp + google.protobuf.Timestamp before = 2; + + // After + // + // Advisories published after timestamp + google.protobuf.Timestamp after = 3; + + // Include unpublished + // + // Whether to include unpublished advisories + // apollo/impl never respects this, but internal services + // may rely on this + google.protobuf.BoolValue include_unpublished = 4; + + // CVE + // + // Only return advisories with given CVE + google.protobuf.StringValue cve = 5; + + // Synopsis + // + // Only return advisories if synopsis contains given text + google.protobuf.StringValue synopsis = 6; + + // Include RPMs + // + // Includes RPMs in list response (slow) + google.protobuf.BoolValue include_rpms = 7; + + // Keyword + // + // Searches all fields for given keyword + google.protobuf.StringValue keyword = 8; + + // Severity + // + // Only return advisories with given severity + Advisory.Severity severity = 9; + + // Type + // + // Only return advisories with given type + Advisory.Type type = 10; + + // Fetch related + // + // Fetch all information related to the advisory (slow) + // Default: true + google.protobuf.BoolValue fetch_related = 11; +} + +// ListAdvisoriesRequest +// +// Request body for `ListAdvisories` +// All fields are optional +message ListAdvisoriesRequest { + // Filters for the given query + // No filters returns all advisories + AdvisoryFilters filters = 1; + + int32 page = 2; + int32 limit = 3 [(validate.rules).int32.lte = 100]; +} + +// ListAdvisoriesResponse +// +// Response body for `ListAdvisories` +message ListAdvisoriesResponse { + repeated Advisory advisories = 1; + + // Total packages from server + int64 total = 2; + + // Limit from request + int32 size = 3; + + // Current page + int32 page = 4; + + // Last updated + google.protobuf.Timestamp last_updated = 5; +} + +// ListAdvisoriesRSSRequest +// Request body for `ListAdvisoriesRSS` +// All fields are optional +message ListAdvisoriesRSSRequest { + // Filters for the given query + // No filters returns all advisories + AdvisoryFilters filters = 1; +} + +// GetAdvisoryRequest +// +// Request body for `GetAdvisory` +message GetAdvisoryRequest { + // ID + // + // Errata ID + // Example: RLSA:2021-1515 + string id = 1 [(validate.rules).string = { + pattern: "^(.+)([SEB]A)-([0-9]{4}):([0-9]+)$", + }]; +} + +// GetAdvisoryResponse +// +// Response body for `GetAdvisory` +message GetAdvisoryResponse { + Advisory advisory = 1; +} diff --git a/apollo/proto/v1/build.proto b/apollo/proto/v1/build.proto new file mode 100644 index 0000000..1ff48c5 --- /dev/null +++ b/apollo/proto/v1/build.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package resf.apollo.v1; + +option go_package = "peridot.resf.org/apollo/pb;apollopb"; + +enum BuildStatus { + BUILD_STATUS_UNKNOWN = 0; + BUILD_STATUS_FIXED = 1; + BUILD_STATUS_NOT_FIXED = 2; + BUILD_STATUS_WILL_NOT_FIX = 3; + BUILD_STATUS_SKIP = 4; +} diff --git a/apollo/proto/v1/cve.proto b/apollo/proto/v1/cve.proto new file mode 100644 index 0000000..f9c8aae --- /dev/null +++ b/apollo/proto/v1/cve.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +package resf.apollo.v1; + +import "google/protobuf/wrappers.proto"; + +option go_package = "peridot.resf.org/apollo/pb;apollopb"; + +message CVE { + string name = 1; + + google.protobuf.StringValue source_by = 2; + google.protobuf.StringValue source_link = 3; + + google.protobuf.StringValue cvss3_scoring_vector = 4; + google.protobuf.StringValue cvss3_base_score = 5; + google.protobuf.StringValue cwe = 6; +} + +message ListUnresolvedCVEsRequest {} +message ListUnresolvedCVEsResponse { + repeated CVE cves = 1; +} + +message ListFixedCVEsRequest {} +message ListFixedCVEsResponse { + repeated CVE cves = 1; +} diff --git a/apollo/proto/v1/fix.proto b/apollo/proto/v1/fix.proto new file mode 100644 index 0000000..6c0e69e --- /dev/null +++ b/apollo/proto/v1/fix.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package resf.apollo.v1; + +import "google/protobuf/wrappers.proto"; + +option go_package = "peridot.resf.org/apollo/pb;apollopb"; + +message Fix { + google.protobuf.StringValue ticket = 1; + google.protobuf.StringValue source_by = 2; + google.protobuf.StringValue source_link = 3; + google.protobuf.StringValue description = 4; +} diff --git a/apollo/proto/v1/short_code.proto b/apollo/proto/v1/short_code.proto new file mode 100644 index 0000000..8f7c9d4 --- /dev/null +++ b/apollo/proto/v1/short_code.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package resf.apollo.v1; + +option go_package = "peridot.resf.org/apollo/pb;apollopb"; + +message ShortCode { + // Code + // + // Full short code + string code = 1; + + enum Mode { + MODE_UNKNOWN = 0; + MODE_PUBLISH = 1; + MODE_MIRROR = 2; + } + // Mode + // + // Mode for short code + // Currently only publish and mirror is supported + Mode mode = 2; + + // Archived + // + // Whether the short code is archived or not + // An archived short code CANNOT be used to issue errata + bool archived = 3; +} diff --git a/apollo/ui/BUILD.bazel b/apollo/ui/BUILD.bazel new file mode 100644 index 0000000..b5738d1 --- /dev/null +++ b/apollo/ui/BUILD.bazel @@ -0,0 +1,60 @@ +load("//rules_resf:defs.bzl", "RESFDEPLOY_OUTS_BASE", "container", "peridot_k8s", "resf_frontend") + +package(default_visibility = ["//visibility:public"]) + +server_deps = ["//common/frontend_server"] + +server_entrypoint = "server/index.mjs" + +server_srcs = glob(["server/**/*.mjs"]) + +resf_frontend( + name = "apollo", + srcs = glob([ + "src/**/*.tsx", + "src/**/*.ts", + ]), + entrypoint = "apollo/ui/src/entrypoint.tsx", + index_html = "//rules_resf/internal/resf_bundle:index_no_mobile.hbs", + server_deps = server_deps, + server_entrypoint = server_entrypoint, + server_srcs = server_srcs, + tailwind_config = "//rules_resf/internal/resf_bundle:tailwind.config.nopreflight.js", + title = "Rocky Enterprise Software Foundation Product Errata", + deps = [ + "//apollo/proto/v1:client_typescript", + "//common/mui", + "//common/ui", + "//tailwind:css", + "@npm//@chakra-ui/react", + "@npm//@chakra-ui/icons", + "@npm//@emotion/unitless", + "@npm//framer-motion", + "@npm//framesync", + "@npm//popmotion", + "@npm//style-value-types", + "@npm//await-to-js", + "@npm//react", + "@npm//react-dom", + "@npm//react-router", + "@npm//react-router-dom", + ], +) + +container( + base = "//bases/bazel/node", + files = [ + ":apollo.bundle", + ], + frontend = True, + image_name = "apollo-frontend", + server_entrypoint = server_entrypoint, + server_files = server_srcs + server_deps, +) + +peridot_k8s( + name = "apollo-frontend", + src = "deploy.jsonnet", + outs = RESFDEPLOY_OUTS_BASE, + deps = ["//ci"], +) diff --git a/apollo/ui/deploy.jsonnet b/apollo/ui/deploy.jsonnet new file mode 100644 index 0000000..9b9b8bb --- /dev/null +++ b/apollo/ui/deploy.jsonnet @@ -0,0 +1,25 @@ +local resfdeploy = import 'ci/resfdeploy.jsonnet'; +local kubernetes = import 'ci/kubernetes.jsonnet'; +local frontend = import 'ci/frontend.jsonnet'; + +local tag = std.extVar('tag'); + +resfdeploy.new({ + name: 'apollo-frontend', + backend: false, + migrate: false, + image: kubernetes.tag($.name), + tag: tag, + env: frontend.server_env, + ports: [ + { + name: 'http', + containerPort: 8086, + protocol: 'TCP', + expose: true, + }, + ], + health: { + port: 8086, + }, +}) diff --git a/apollo/ui/server/index.mjs b/apollo/ui/server/index.mjs new file mode 100644 index 0000000..2fd6828 --- /dev/null +++ b/apollo/ui/server/index.mjs @@ -0,0 +1,61 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import server from '../../../common/frontend_server/index.mjs'; +import { + svcNameHttp, + endpointHttp, + NS, +} from '../../../common/frontend_server/upstream.mjs'; + +export default async function run(webpackConfig) { + const devFrontendUrl = 'http://errata.pdot.localhost:9007'; + const envPublicUrl = process.env['APOLLO_FRONTEND_HTTP_PUBLIC_URL']; + const frontendUrl = process.env['RESF_NS'] ? envPublicUrl : devFrontendUrl; + + server({ + baseURL: frontendUrl, + apis: { + '/api': { + prodApiUrl: 'http://apollo-server.apollo2production.svc.cluster.local:8000', + devApiUrl: `https://apollo-dev.internal.pdev.resf.localhost`, + }, + }, + port: 9007, + disableAuth: true, + webpackConfig, + }).then(); +} + +if (process.env.NODE_ENV === 'production') { + run().then(); +} diff --git a/apollo/ui/src/api.ts b/apollo/ui/src/api.ts new file mode 100644 index 0000000..058442f --- /dev/null +++ b/apollo/ui/src/api.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import * as apollo from 'bazel-bin/apollo/proto/v1/client_typescript'; + +export const api = new apollo.ApolloServiceApi( + new apollo.Configuration({ + basePath: '/api', // Points to frontend API proxy + }) +); diff --git a/apollo/ui/src/components/Overview.tsx b/apollo/ui/src/components/Overview.tsx new file mode 100644 index 0000000..ec1d3a0 --- /dev/null +++ b/apollo/ui/src/components/Overview.tsx @@ -0,0 +1,521 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import { + AddIcon, + ArrowLeftIcon, + ArrowRightIcon, + MinusIcon, + SearchIcon, +} from '@chakra-ui/icons'; +import { + Alert, + AlertDescription, + AlertIcon, + AlertTitle, + Box, + ButtonGroup, + FormControl, + FormLabel, + HStack, + IconButton, + Input, + InputGroup, + InputLeftElement, + Link, + Select, + Spinner, + Stack, + Table, + TableColumnHeaderProps, + TableContainer, + Tbody, + Td, + Text, + Th, + Thead, + Tr, + useColorModeValue, +} from '@chakra-ui/react'; +import { + severityToBadge, + severityToText, + typeToText, +} from 'apollo/ui/src/enumToText'; +import { + ListAdvisoriesFiltersSeverityEnum, + ListAdvisoriesFiltersTypeEnum, +} from 'bazel-bin/apollo/proto/v1/client_typescript'; +import { + V1Advisory, + V1AdvisoryType, +} from 'bazel-bin/apollo/proto/v1/client_typescript/models'; +import { reqap } from 'common/ui/reqap'; +import React, { useEffect, useState } from 'react'; +import { Link as RouterLink } from 'react-router-dom'; + +import { api } from '../api'; +import { COLOR_RESF_GREEN } from '../styles'; + +export const Overview = () => { + const inputBackground = useColorModeValue('white', undefined); + + const tableBg = useColorModeValue('white', 'gray.800'); + const pagerButtonScheme = useColorModeValue('blackAlpha', 'gray'); + const linkBlue = useColorModeValue('blue.600', 'blue.300'); + const linkPurple = useColorModeValue('purple.600', 'purple.300'); + + const [advisories, setAdvisories] = useState(); + const [lastUpdated, setLastUpdated] = useState(); + const [total, setTotal] = useState(0); + const [isLoading, setIsLoading] = useState(true); + const [isError, setIsError] = useState(false); + + // Request State + const [page, setPage] = useState(0); + const [pageSize, setPageSize] = useState(25); + const [filtersKeyword, setFiltersKeyword] = useState(); + const [filterBefore, setFilterBefore] = useState(); + const [filterAfter, setFilterAfter] = useState(); + const [filterProduct, setFilterProduct] = useState(''); + const [filtersType, setFiltersType] = + useState(); + const [filtersSeverity, setFiltersSeverity] = + useState(); + + useEffect(() => { + const fetch = async () => { + setIsLoading(true); + const [err, res] = await reqap(() => + api.listAdvisories({ + page, + limit: pageSize, + filtersKeyword, + filtersFetchRelated: false, + filtersBefore: filterBefore, + filtersAfter: filterAfter, + filtersProduct: filterProduct, + filtersSeverity: filtersSeverity + ? ListAdvisoriesFiltersSeverityEnum[filtersSeverity] + : undefined, + filtersType: filtersType + ? ListAdvisoriesFiltersTypeEnum[filtersType] + : undefined, + }) + ); + + setIsLoading(false); + + if (err || !res) { + setIsError(true); + setAdvisories(undefined); + return; + } + + setIsError(false); + + if (res) { + setAdvisories(res.advisories); + setLastUpdated(res.lastUpdated); + setTotal(parseInt(res.total || '0')); + } + }; + + const timer = setTimeout(() => fetch(), 500); + + return () => clearTimeout(timer); + }, [ + pageSize, + page, + filtersKeyword, + filterBefore, + filterAfter, + filtersSeverity, + filterProduct, + filtersType, + ]); + + // TODO: Figure out why sticky isn't sticking + const stickyProps: TableColumnHeaderProps = { + position: 'sticky', + top: '0px', + zIndex: '10', + scope: 'col', + }; + + const lastPage = total < pageSize ? 0 : Math.ceil(total / pageSize) - 1; + + return ( + + + + + + + setFiltersKeyword(e.target.value)} + /> + + + + Type + + + {filtersType === 'Security' && ( + + Severity + + + )} + + Product + + + + + + From + { + const newVal = e.currentTarget.value; + console.log(newVal); + + if (!newVal) { + setFilterAfter(undefined); + } + + const asDate = new Date(newVal); + if (!(asDate instanceof Date) || isNaN(asDate.getTime())) { + // Check value parses as a date + return; + } + + const [year, month, date] = newVal.split('-').map(Number); + + setFilterAfter(new Date(year, month - 1, date)); + }} + /> + + + To + { + const newVal = e.currentTarget.value; + + if (!newVal) { + setFilterBefore(undefined); + } + + const asDate = new Date(newVal); + if (!(asDate instanceof Date) || isNaN(asDate.getTime())) { + // Check value parses as a date + return; + } + + const [year, month, date] = newVal.split('-').map(Number); + + setFilterBefore( + new Date(year, month - 1, date, 23, 59, 59, 59) // Set to 1ms prior to midnight to be inclusive of selected date + ); + }} + /> + + + + + + Last updated {lastUpdated?.toLocaleString() || 'never'} + + + + Displaying {(page * pageSize + 1).toLocaleString()}- + {Math.min(total, page * pageSize + pageSize).toLocaleString()} of{' '} + {total.toLocaleString()} + + + } + disabled={page <= 0} + onClick={() => setPage(0)} + /> + } + disabled={page <= 0} + onClick={() => setPage((old) => old - 1)} + /> + + {(page + 1).toLocaleString()} / {(lastPage + 1).toLocaleString()} + + } + disabled={page >= lastPage} + onClick={() => setPage((old) => old + 1)} + /> + } + disabled={page >= lastPage} + onClick={() => setPage(lastPage)} + /> + + + + {isLoading ? ( + + ) : isError ? ( + + + Something has gone wrong + Failed to load errata + + ) : ( + + + + + + + + + + + + + + {!advisories?.length && ( + + + + )} + {advisories?.map((a, idx) => ( + + + + + + + + + ))} + +
+ AdvisorySynopsisType / SeverityProductsIssue Date
+ No rows found +
+ {severityToBadge(a.severity, a.type)} + + + {a.name} + + + {a.synopsis?.replace( + /^(Critical|Important|Moderate|Low): /, + '' + )} + + {typeToText(a.type)} + {a.type === V1AdvisoryType.Security + ? ` / ${severityToText(a.severity)}` + : ''} + {a.affectedProducts?.join(', ')} + {Intl.DateTimeFormat(undefined, { + day: '2-digit', + month: 'short', + year: 'numeric', + }).format(a.publishedAt)} +
+
+
+ )} + + + Rows per page: + + + +
+ ); +}; diff --git a/apollo/ui/src/components/Root.tsx b/apollo/ui/src/components/Root.tsx new file mode 100644 index 0000000..a6117a3 --- /dev/null +++ b/apollo/ui/src/components/Root.tsx @@ -0,0 +1,150 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import { MoonIcon, SunIcon } from '@chakra-ui/icons'; +import { + Box, + HStack, + Text, + Link as ChakraLink, + useColorMode, + IconButton, + useColorModeValue, + DarkMode, +} from '@chakra-ui/react'; +import { RESFLogo } from 'common/ui/RESFLogo'; +import React from 'react'; +import { Route, Switch } from 'react-router'; +import { Link } from 'react-router-dom'; + +import { COLOR_RESF_BLUE, COLOR_RESF_GREEN } from '../styles'; +import { Overview } from './Overview'; +import { ShowErrata } from './ShowErrata'; + +export const Root = () => { + const { colorMode, toggleColorMode } = useColorMode(); + + const SwitchIcon = useColorModeValue(MoonIcon, SunIcon); + const bodyBg = useColorModeValue('gray.100', 'gray.900'); + + return ( + + + + + + + Product Errata + + + + + } + /> + + + + + + + + + + + + + + + RSS + + + + ); +}; diff --git a/apollo/ui/src/components/ShowErrata.tsx b/apollo/ui/src/components/ShowErrata.tsx new file mode 100644 index 0000000..a1efd7e --- /dev/null +++ b/apollo/ui/src/components/ShowErrata.tsx @@ -0,0 +1,343 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import { + Alert, + AlertDescription, + AlertIcon, + AlertTitle, + Box, + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + Heading, + HStack, + Link, + ListItem, + Spinner, + Tab, + TabList, + TabPanel, + TabPanels, + Tabs, + Text, + UnorderedList, + useColorModeValue, + VStack, +} from '@chakra-ui/react'; +import { + severityToBadge, + severityToText, + typeToText, +} from 'apollo/ui/src/enumToText'; +import { + V1Advisory, + V1AdvisoryType, +} from 'bazel-bin/apollo/proto/v1/client_typescript'; +import { reqap } from 'common/ui/reqap'; +import React, { useState } from 'react'; +import { RouteComponentProps } from 'react-router'; +import { Link as RouterLink } from 'react-router-dom'; + +import { api } from '../api'; +import { COLOR_RESF_GREEN } from '../styles'; + +interface ShowErrataParams { + id: string; +} + +export interface ShowErrataProps + extends RouteComponentProps {} + +export const ShowErrata = (props: ShowErrataProps) => { + const id = props.match.params.id; + + const cardBg = useColorModeValue('white', 'gray.800'); + const sideBg = useColorModeValue('gray.100', 'gray.700'); + const linkBlue = useColorModeValue('blue.600', 'blue.300'); + const linkPurple = useColorModeValue('purple.600', 'purple.300'); + + const [errata, setErrata] = useState(); + const [isLoading, setIsLoading] = useState(true); + const [isError, setIsError] = useState(false); + + React.useEffect(() => { + const fetch = async () => { + setIsLoading(true); + + const [err, res] = await reqap(() => api.getAdvisory({ id })); + + setIsLoading(false); + + if (err || !res) { + setIsError(true); + setErrata(undefined); + return; + } + + setIsError(false); + + setErrata(res.advisory); + }; + + fetch(); + }, [id]); + + return ( + + + + + Product Errata + + + + {id} + + + {isLoading ? ( + + ) : isError ? ( + + + Something has gone wrong + Failed to load errata + + ) : ( + errata && ( + <> + + {severityToBadge(errata.severity, errata.type, 40)} + + + + {errata.name} + + + {errata.synopsis} + + + + + Erratum + Affected Packages + + + + + + Topic + + {errata.topic?.split('\n').map((p, i) => ( + + {p} + + ))} + + Description + + {errata.description?.split('\n').map((p, i) => ( + + {p} + + ))} + + + + {Object.keys(errata.rpms || {}).map((product) => ( +
+ + {product} + + + SRPMs + + + {errata.rpms?.[product]?.nvras + ?.filter((x) => x.indexOf('.src.rpm') !== -1) + .map((x) => ( + {x} + ))} + + + RPMs + + + {errata.rpms?.[product]?.nvras + ?.filter((x) => x.indexOf('.src.rpm') === -1) + .map((x) => ( + {x} + ))} + +
+ ))} +
+
+
+ + + Issued: {errata.publishedAt?.toLocaleDateString()} + + + Type: {typeToText(errata.type)} + + {errata.type === V1AdvisoryType.Security && ( + + Severity: {severityToText(errata.severity)} + + )} + + + Affected Product + {(errata.affectedProducts?.length || 0) > 1 ? 's' : ''} + + + {errata.affectedProducts?.map((x, idx) => ( + {x} + ))} + + + + Fixes + + {errata.fixes?.map((x, idx) => ( + + + {x.sourceBy} - {x.ticket} + + + ))} + + + + CVEs + + {!!errata.cves?.length ? ( + errata.cves?.map((x, idx) => { + let text = `${x.name}${ + x.sourceBy !== '' && ` (Source: ${x.sourceBy})` + }`; + + return ( + + {x.sourceLink === '' ? ( + {text} + ) : ( + + {text} + + )} + + ); + }) + ) : ( + No CVEs + )} + + + + References + + {!!errata.references?.length ? ( + errata.references?.map((x, idx) => ( + {x} + )) + ) : ( + No references + )} + + + +
+
+ + ) + )} +
+ ); +}; diff --git a/apollo/ui/src/entrypoint.tsx b/apollo/ui/src/entrypoint.tsx new file mode 100644 index 0000000..6b351e3 --- /dev/null +++ b/apollo/ui/src/entrypoint.tsx @@ -0,0 +1,61 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import 'tailwind/tailwind.css'; + +import { ChakraProvider, ColorModeScript } from '@chakra-ui/react'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { BrowserRouter } from 'react-router-dom'; + +import { Root } from './components/Root'; +import theme from './theme'; + +export const app = () => { + ReactDOM.render( + <> + + + + + + + , + document.getElementById('root') + ); +}; + +app(); + +if (module.hot) { + module.hot.accept(app); +} diff --git a/apollo/ui/src/enumToText.tsx b/apollo/ui/src/enumToText.tsx new file mode 100644 index 0000000..8fcb848 --- /dev/null +++ b/apollo/ui/src/enumToText.tsx @@ -0,0 +1,182 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import { Box, Tag, TagProps, Tooltip } from '@chakra-ui/react'; +import { + AdvisorySeverity, + V1AdvisoryType, +} from 'bazel-bin/apollo/proto/v1/client_typescript'; +import React from 'react'; + +export const severityToText = (severity?: AdvisorySeverity): string => { + switch (severity) { + case AdvisorySeverity.Critical: + return 'Critical'; + case AdvisorySeverity.Important: + return 'Important'; + case AdvisorySeverity.Moderate: + return 'Moderate'; + case AdvisorySeverity.Low: + return 'Low'; + default: + return 'None'; + } +}; + +export const severityToBadge = ( + severity: AdvisorySeverity | undefined, + type: V1AdvisoryType | undefined, + size: number = 20 +): React.ReactNode => { + return ( + + { + { + [AdvisorySeverity.Critical]: ( + + + + + + + ), + [AdvisorySeverity.Important]: ( + + + + + + + ), + [AdvisorySeverity.Moderate]: ( + + + + + ), + [AdvisorySeverity.Low]: ( + + + + + + + ), + [AdvisorySeverity.Unknown]: ( + + + + + + + + ), + }[severity || AdvisorySeverity.Unknown] + } + + ); +}; + +export const typeToText = (type?: V1AdvisoryType): string => { + switch (type) { + case V1AdvisoryType.Bugfix: + return 'Bug Fix'; + case V1AdvisoryType.Security: + return 'Security'; + case V1AdvisoryType.Enhancement: + return 'Enhancement'; + default: + return 'Unknown'; + } +}; diff --git a/apollo/ui/src/styles.ts b/apollo/ui/src/styles.ts new file mode 100644 index 0000000..2008bb7 --- /dev/null +++ b/apollo/ui/src/styles.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +export const COLOR_RESF_GREEN = '#10B981'; +export const COLOR_RESF_BLUE = '#1054B9'; diff --git a/apollo/ui/src/theme.ts b/apollo/ui/src/theme.ts new file mode 100644 index 0000000..d4b9e50 --- /dev/null +++ b/apollo/ui/src/theme.ts @@ -0,0 +1,52 @@ +/* + * Copyright (c) All respective contributors to the Peridot Project. All rights reserved. + * Copyright (c) 2021-2022 Rocky Enterprise Software Foundation, Inc. All rights reserved. + * Copyright (c) 2021-2022 Ctrl IQ, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +import { extendTheme, type Theme, type ThemeConfig } from '@chakra-ui/react'; + +const config: ThemeConfig = { + initialColorMode: 'system', +}; + +const styles: Theme['styles'] = { + global: (props) => ({ + ':root': { + colorScheme: props.colorMode, + }, + }), +}; + +const theme = extendTheme({ + config, + styles, +}); + +export default theme; diff --git a/spicedb/deploy/common.jsonnet b/spicedb/deploy/common.jsonnet index 8f4713a..575ace5 100644 --- a/spicedb/deploy/common.jsonnet +++ b/spicedb/deploy/common.jsonnet @@ -6,7 +6,7 @@ local DSN = db.dsn('hydra'); { image: 'quay.io/peridot/spicedb', - tag: 'v0.2.16', + tag: 'v0.3.21', legacyDb: true, dsn: { name: 'DSN', diff --git a/spicedb/deploy/deploy.jsonnet b/spicedb/deploy/deploy.jsonnet index 53ffd8a..0c5f874 100644 --- a/spicedb/deploy/deploy.jsonnet +++ b/spicedb/deploy/deploy.jsonnet @@ -19,15 +19,6 @@ resfdeploy.new({ image: common.image, tag: common.tag, dsn: common.dsn, - internal_route_options: { - headers: { - request: { - add: { - 'Authorization': 'Bearer %s' % common.env[0].value, - } - } - } - }, requests: if kubernetes.prod() then { cpu: '0.2', memory: '512M',