diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..795c932 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @flashcatcloud/flashduty-sdk diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..99c1fc5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: "\U0001F41B Bug report" +about: Report a bug or unexpected behavior while using Flashduty SDK +title: '' +labels: bug +assignees: '' + +--- + +### Describe the bug + +A clear and concise description of what the bug is. + +### Affected version + +Which version (Git tag or commit) of `flashduty-sdk` are you using? Include your Go version (`go version`). + +### Steps to reproduce the behavior + +1. Call this method '...' +2. With these inputs '....' +3. See error + +A minimal, self-contained code snippet that reproduces the issue is the most helpful. + +### Expected vs actual behavior + +A clear and concise description of what you expected to happen and what actually happened. + +### Logs + +Paste any available logs or output. Redact app keys and other secrets if needed. + +Closes: diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..adfa05b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,24 @@ +--- +name: "⭐ Submit a feature request" +about: Surface a feature or problem that you think should be solved +title: '' +labels: enhancement +assignees: '' + +--- + +### Describe the feature or problem you'd like to solve + +A clear and concise description of what the feature or problem is. + +### Proposed solution + +How will it benefit Flashduty SDK and its users? + +### Example usage + +If it's a new method or improvement, share a code snippet showing how you'd expect to use it. Just enough detail to show the value. + +### Additional context + +Add any other context here, if applicable. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..99774ea --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..83ec329 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,10 @@ + + +Closes: diff --git a/.github/workflows/code-scanning.yml b/.github/workflows/code-scanning.yml new file mode 100644 index 0000000..6282a92 --- /dev/null +++ b/.github/workflows/code-scanning.yml @@ -0,0 +1,50 @@ +name: "CodeQL" + +on: [push, pull_request, workflow_dispatch] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-22.04 + permissions: + actions: read + contents: read + packages: read + security-events: write + strategy: + fail-fast: false + matrix: + include: + - language: actions + category: /language:actions + build-mode: none + - language: go + category: /language:go + build-mode: autobuild + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + - name: Setup Go + uses: actions/setup-go@v5 + if: matrix.language == 'go' + with: + go-version-file: "go.mod" + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: ${{ matrix.category }} diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..6c79cac --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,32 @@ +name: Build and Test Go Project +on: [push, pull_request] + +permissions: + contents: read + +jobs: + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + runs-on: ${{ matrix.os }} + + steps: + - name: Check out code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + + - name: Download dependencies + run: go mod download + + - name: Run unit tests + run: go test -race ./... + + - name: Build + run: go build -v ./... diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..e85dfa4 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: golangci-lint +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: stable + - name: golangci-lint + uses: golangci/golangci-lint-action@v8 + with: + version: v2.11 diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..caa230e --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,51 @@ +# https://golangci-lint.run/usage/configuration +version: "2" + +run: + timeout: 5m + tests: true + concurrency: 4 + +linters: + enable: + - govet + - errcheck + - staticcheck + - revive + - ineffassign + - unused + - misspell + - nakedret + - bodyclose + - gocritic + - makezero + - gosec + settings: + staticcheck: + checks: + - all + - '-QF1008' # Allow embedded structs to be referenced by field + - '-ST1000' # Do not require package comments + revive: + rules: + - name: exported + disabled: true + - name: package-comments + disabled: true + exclusions: + rules: + # Test fixtures use hardcoded fake credentials and read fixture paths. + - path: _test\.go + linters: + - gosec + +formatters: + enable: + - gofmt + - goimports + +output: + formats: + text: + print-linter-name: true + print-issued-lines: true diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d862ada --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,12 @@ +# Code of Conduct + +This project has adopted the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1, as its Code of Conduct. Contributors and participants are expected to uphold it. + +The full text is available at: + +- English: https://www.contributor-covenant.org/version/2/1/code_of_conduct/ +- 中文: https://www.contributor-covenant.org/zh-cn/version/2/1/code_of_conduct/ + +## Enforcement + +Instances of abusive or otherwise unacceptable behavior may be reported to the project maintainers at [support@flashcat.cloud](mailto:support@flashcat.cloud). All complaints will be reviewed and investigated promptly and fairly. Maintainers are obligated to respect the privacy and security of the reporter of any incident. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2b190c6 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing + +Hi there! We're thrilled that you'd like to contribute to Flashduty SDK. Your help is essential for keeping it great. + +Contributions to this project are [released](https://docs.github.com/site-policy/github-terms/github-terms-of-service#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). + +Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. + +## Prerequisites for running and testing code + +These are one-time installations required to test your changes locally as part of the pull request (PR) submission process. + +1. Install Go — [download](https://go.dev/doc/install) or [via Homebrew](https://formulae.brew.sh/formula/go). See `go.mod` for the minimum required version. +2. [Install golangci-lint v2](https://golangci-lint.run/welcome/install/). + +## Submitting a pull request + +1. [Fork](https://github.com/flashcatcloud/flashduty-sdk/fork) and clone the repository. +2. Make sure the tests pass on your machine: `go test -race ./...` +3. Make sure the linter passes on your machine: `golangci-lint run` +4. Create a new branch: `git checkout -b my-branch-name` +5. Make your change, add tests, and make sure the tests and linter still pass. +6. Push to your fork and [submit a pull request](https://github.com/flashcatcloud/flashduty-sdk/compare) targeting the `main` branch. +7. Pat yourself on the back and wait for your pull request to be reviewed and merged. + +Here are a few things you can do that will increase the likelihood of your pull request being accepted: + +- Write tests. +- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. +- Write a [good commit message](https://cbea.ms/git-commit/). + +## Resources + +- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) +- [Using Pull Requests](https://docs.github.com/pull-requests) +- [GitHub Help](https://docs.github.com) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d2db26d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 flashcatcloud + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index f0fae94..13e9204 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ -# flashduty-sdk +# Flashduty SDK + +English | [中文](README_zh.md) + +[![License](https://img.shields.io/github/license/flashcatcloud/flashduty-sdk?style=flat-square&color=24bfa5&label=License)](LICENSE) +[![Go Reference](https://img.shields.io/badge/Go-Reference-24bfa5?style=flat-square&logo=go)](https://pkg.go.dev/github.com/flashcatcloud/flashduty-sdk) +[![CI](https://img.shields.io/github/actions/workflow/status/flashcatcloud/flashduty-sdk/go.yml?style=flat-square&branch=main&label=CI)](https://github.com/flashcatcloud/flashduty-sdk/actions) +[![Go Report Card](https://goreportcard.com/badge/github.com/flashcatcloud/flashduty-sdk?style=flat-square)](https://goreportcard.com/report/github.com/flashcatcloud/flashduty-sdk) Go SDK for the [Flashduty](https://flashcat.cloud) API. Provides typed methods for incident management, on-call scheduling, status pages, notification templates, and more. @@ -266,6 +273,23 @@ if err != nil { } ``` +## Development + +Requires Go 1.24+ and [golangci-lint v2](https://golangci-lint.run/welcome/install/). + +```bash +go test -race ./... # Run tests with race detection +golangci-lint run # Run the linter +``` + +## Contributing + +Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request, and note our [Code of Conduct](CODE_OF_CONDUCT.md). + +- [Report a bug or request a feature](https://github.com/flashcatcloud/flashduty-sdk/issues/new/choose) +- [Get help and support](SUPPORT.md) +- [Report a security vulnerability](SECURITY.md) + ## License -See [LICENSE](LICENSE) for details. +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..f84d99f --- /dev/null +++ b/README_zh.md @@ -0,0 +1,295 @@ +# Flashduty SDK + +[English](README.md) | 中文 + +[![License](https://img.shields.io/github/license/flashcatcloud/flashduty-sdk?style=flat-square&color=24bfa5&label=License)](LICENSE) +[![Go Reference](https://img.shields.io/badge/Go-Reference-24bfa5?style=flat-square&logo=go)](https://pkg.go.dev/github.com/flashcatcloud/flashduty-sdk) +[![CI](https://img.shields.io/github/actions/workflow/status/flashcatcloud/flashduty-sdk/go.yml?style=flat-square&branch=main&label=CI)](https://github.com/flashcatcloud/flashduty-sdk/actions) +[![Go Report Card](https://goreportcard.com/badge/github.com/flashcatcloud/flashduty-sdk?style=flat-square)](https://goreportcard.com/report/github.com/flashcatcloud/flashduty-sdk) + +[Flashduty](https://flashcat.cloud) 平台 API 的 Go SDK。提供故障管理、值班排班、状态页、通知模板等能力的类型化方法。 + +## 安装 + +```bash +go get github.com/flashcatcloud/flashduty-sdk +``` + +需要 Go 1.24+。 + +## 快速开始 + +```go +package main + +import ( + "context" + "fmt" + "log" + + flashduty "github.com/flashcatcloud/flashduty-sdk" +) + +func main() { + client, err := flashduty.NewClient("your-app-key") + if err != nil { + log.Fatal(err) + } + + incidents, err := client.ListIncidents(context.Background(), &flashduty.ListIncidentsInput{ + Progress: "Triggered", + StartTime: 1710000000, + EndTime: 1710086400, + }) + if err != nil { + log.Fatal(err) + } + + for _, inc := range incidents.Incidents { + fmt.Printf("[%s] %s (channel: %s)\n", inc.Severity, inc.Title, inc.ChannelName) + } +} +``` + +## 客户端选项 + +```go +client, err := flashduty.NewClient("your-app-key", + flashduty.WithBaseURL("https://custom-api.example.com"), + flashduty.WithTimeout(10 * time.Second), + flashduty.WithUserAgent("my-app/1.0"), + flashduty.WithHTTPClient(customHTTPClient), + flashduty.WithLogger(myLogger), + flashduty.WithRequestHeaders(staticHeaders), + flashduty.WithRequestHook(func(req *http.Request) { + // 注入按请求的请求头(例如 W3C Trace Context) + req.Header.Set("traceparent", traceID) + }), +) +``` + +| 选项 | 默认值 | 说明 | +|------|--------|------| +| `WithBaseURL` | `https://api.flashcat.cloud` | API 地址 | +| `WithTimeout` | `30s` | HTTP 客户端超时 | +| `WithUserAgent` | `flashduty-go-sdk` | User-Agent 请求头 | +| `WithHTTPClient` | 默认 `http.Client` | 自定义 HTTP 客户端 | +| `WithLogger` | 基于 `slog` 的日志器 | 实现 `Logger` 接口的自定义日志器 | +| `WithRequestHeaders` | 无 | 每个请求都包含的静态请求头 | +| `WithRequestHook` | 无 | 每个出站请求发送前调用的回调 | + +### 动态 User-Agent + +创建客户端之后仍可更新 User-Agent(例如按会话): + +```go +client.SetUserAgent("my-app/2.0 (client-name/1.2)") +``` + +## 日志接口 + +SDK 使用可插拔的日志器,默认实现封装了 `log/slog`。 + +```go +type Logger interface { + Debug(msg string, keysAndValues ...any) + Info(msg string, keysAndValues ...any) + Warn(msg string, keysAndValues ...any) + Error(msg string, keysAndValues ...any) +} +``` + +适配 logrus 或其他后端: + +```go +type logrusAdapter struct{ *logrus.Logger } + +func (a *logrusAdapter) Info(msg string, kv ...any) { a.WithFields(kvToFields(kv)).Info(msg) } +func (a *logrusAdapter) Warn(msg string, kv ...any) { a.WithFields(kvToFields(kv)).Warn(msg) } +func (a *logrusAdapter) Error(msg string, kv ...any) { a.WithFields(kvToFields(kv)).Error(msg) } +func (a *logrusAdapter) Debug(msg string, kv ...any) { a.WithFields(kvToFields(kv)).Debug(msg) } + +func kvToFields(kv []any) logrus.Fields { + fields := make(logrus.Fields, len(kv)/2) + for i := 0; i+1 < len(kv); i += 2 { + if key, ok := kv[i].(string); ok { + fields[key] = kv[i+1] + } + } + return fields +} +``` + +## API 参考 + +### 故障(Incidents) + +```go +// 按 ID 或筛选条件列出故障(基于时间的查询需要 StartTime 和 EndTime) +client.ListIncidents(ctx, &ListIncidentsInput{...}) (*ListIncidentsOutput, error) + +// 获取一个或多个故障的时间线事件 +client.GetIncidentTimelines(ctx, incidentIDs) ([]IncidentTimelineOutput, error) + +// 获取一个或多个故障的告警 +client.ListIncidentAlerts(ctx, incidentIDs, limit) ([]IncidentAlertsOutput, error) + +// 查找相似的历史故障 +client.ListSimilarIncidents(ctx, incidentID, limit) (*ListIncidentsOutput, error) + +// 创建新故障 +client.CreateIncident(ctx, &CreateIncidentInput{...}) (any, error) + +// 更新故障字段(标题、描述、级别、自定义字段) +client.UpdateIncident(ctx, &UpdateIncidentInput{...}) ([]string, error) + +// 认领故障 +client.AckIncidents(ctx, incidentIDs) error + +// 关闭(解决)故障 +client.CloseIncidents(ctx, incidentIDs) error +``` + +### 成员(Members) + +```go +// 按人员 ID、姓名或邮箱列出成员 +client.ListMembers(ctx, &ListMembersInput{...}) (*ListMembersOutput, error) +``` + +### 团队(Teams) + +```go +// 按团队 ID 或名称列出团队 +client.ListTeams(ctx, &ListTeamsInput{...}) (*ListTeamsOutput, error) +``` + +### 协作空间(Channels) + +```go +// 按 ID 或名称列出协作空间(名称匹配为不区分大小写的子串匹配) +client.ListChannels(ctx, &ListChannelsInput{...}) (*ListChannelsOutput, error) +``` + +### 分派策略(Escalation Rules) + +```go +// 列出某协作空间的分派策略(附带人员/团队/排班名称) +client.ListEscalationRules(ctx, channelID) (*ListEscalationRulesOutput, error) +``` + +### 自定义字段(Custom Fields) + +```go +// 列出自定义字段定义,可按 ID 或名称筛选 +client.ListFields(ctx, &ListFieldsInput{...}) (*ListFieldsOutput, error) +``` + +### 变更记录(Changes) + +```go +// 列出变更记录(部署、配置等),附带解析后的名称 +client.ListChanges(ctx, &ListChangesInput{...}) (*ListChangesOutput, error) +``` + +### 状态页(Status Pages) + +```go +// 列出状态页,可按页面 ID 筛选 +client.ListStatusPages(ctx, pageIDs) ([]StatusPage, error) + +// 列出状态页上活跃的事件或维护 +client.ListStatusChanges(ctx, &ListStatusChangesInput{...}) (*ListStatusChangesOutput, error) + +// 在状态页上创建事件 +client.CreateStatusIncident(ctx, &CreateStatusIncidentInput{...}) (any, error) + +// 为状态页事件或维护添加时间线更新 +client.CreateChangeTimeline(ctx, &CreateChangeTimelineInput{...}) error +``` + +### 通知模板(Templates) + +```go +// 获取某渠道的预设(默认)通知模板 +client.GetPresetTemplate(ctx, &GetPresetTemplateInput{...}) (*GetPresetTemplateOutput, error) + +// 校验并预览通知模板,含大小限制检查 +client.ValidateTemplate(ctx, &ValidateTemplateInput{...}) (*ValidateTemplateOutput, error) +``` + +#### 静态模板数据 + +以下包级函数返回编译进 SDK 的参考数据,用于编写模板: + +```go +// 可用的模板变量(7 个分类共 40 个变量) +flashduty.TemplateVariables() []TemplateVariable + +// Flashduty 自定义模板函数(19 个) +flashduty.TemplateCustomFunctions() []TemplateFunction + +// 常用的 Sprig 模板函数(19 个) +flashduty.TemplateSprigFunctions() []TemplateFunction + +// 合法的通知渠道标识(13 个渠道) +flashduty.ChannelEnumValues() []string +``` + +支持的通知渠道:`dingtalk`、`dingtalk_app`、`feishu`、`feishu_app`、`wecom`、`wecom_app`、`slack`、`slack_app`、`telegram`、`teams_app`、`email`、`sms`、`zoom`。 + +渠道大小限制与渠道-字段映射分别通过 `flashduty.ChannelSizeLimits` 和 `flashduty.TemplateChannels` 提供。 + +> **注意:** 静态模板数据编译在 SDK 内,平台侧新增项需要随 SDK 发版才能获取。 + +## 数据补全(Enrichment) + +大多数查询方法会自动用可读名称补全原始 API 数据。例如 `ListIncidents` 会把 `CreatorID` 解析为 `CreatorName`、`ChannelID` 解析为 `ChannelName`、响应人的人员 ID 解析为姓名和邮箱。 + +补全通过 `errgroup` 并发批量拉取。对 `ListChanges`、`ListChannels` 等方法,补全采用尽力而为策略——即使名称解析失败,主数据仍会返回。 + +## 输出格式 + +SDK 支持 JSON 与 [TOON](https://github.com/toon-format/toon-go)(Token-Oriented Object Notation)序列化: + +```go +data, err := flashduty.Marshal(incidents, flashduty.OutputFormatJSON) +data, err := flashduty.Marshal(incidents, flashduty.OutputFormatTOON) + +format := flashduty.ParseOutputFormat("toon") // 未知值默认回退到 JSON +``` + +## 错误处理 + +API 错误以 `*DutyError` 返回,它实现了 `error` 接口: + +```go +incidents, err := client.ListIncidents(ctx, input) +if err != nil { + var dutyErr *flashduty.DutyError + if errors.As(err, &dutyErr) { + fmt.Printf("API error [%s]: %s\n", dutyErr.Code, dutyErr.Message) + } +} +``` + +## 开发 + +需要 Go 1.24+ 和 [golangci-lint v2](https://golangci-lint.run/welcome/install/)。 + +```bash +go test -race ./... # 运行测试(启用竞态检测) +golangci-lint run # 运行代码检查 +``` + +## 参与贡献 + +欢迎贡献代码!提交 Pull Request 前请阅读 [CONTRIBUTING.md](CONTRIBUTING.md),并遵守我们的[行为准则](CODE_OF_CONDUCT.md)。 + +- [报告缺陷或提交需求](https://github.com/flashcatcloud/flashduty-sdk/issues/new/choose) +- [获取帮助与支持](SUPPORT.md) +- [报告安全漏洞](SECURITY.md) + +## 许可证 + +本项目基于 MIT 许可证开源 - 详见 [LICENSE](LICENSE) 文件。 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..40f9db8 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,33 @@ +Thanks for helping make Flashduty safe for everyone. + +# Security + +Flashduty takes the security of our software products and services seriously, including all of the open source code repositories managed through our organizations, such as [Flashcat](https://github.com/flashcatcloud). + +Even though open source repositories are outside of the scope of our bug bounty program and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation. + +## Reporting Security Issues + +If you believe you have found a security vulnerability in any Flashduty-owned repository, please report it to us through coordinated disclosure. + +**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** + +Instead, please send an email to [support@flashcat.cloud](mailto:support@flashcat.cloud). + +Please include as much of the information listed below as you can to help us better understand and resolve the issue: + + * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Policy + +Flashduty is committed to responsible security vulnerability disclosure. We pledge to work with security researchers to resolve reported vulnerabilities in a timely manner and to publicly acknowledge their contributions when appropriate. + +We will not take legal action against researchers who report security vulnerabilities in good faith, provided they follow our disclosure guidelines. diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 0000000..f09a2a6 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,13 @@ +# Support + +## How to file issues and get help + +This project uses GitHub issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new issue. + +For help or questions about using this project, please open an issue. + +- `flashduty-sdk` is under active development and maintained by Flashcat staff **AND THE COMMUNITY**. We will do our best to respond to support, feature requests, and community questions in a timely manner. + +## Flashduty Support Policy + +Support for this project is limited to the resources listed above. diff --git a/helpers.go b/helpers.go index 555ee81..0457e93 100644 --- a/helpers.go +++ b/helpers.go @@ -1,7 +1,6 @@ package flashduty import ( - "strconv" "strings" ) @@ -33,22 +32,3 @@ func mergeChannelIDs(channelIDs []int64, channelID int64) []int64 { } return nil } - -func parseCommaSeparatedInts(s string) []int { - if s == "" { - return nil - } - parts := strings.Split(s, ",") - result := make([]int, 0, len(parts)) - for _, part := range parts { - part = strings.TrimSpace(part) - if part == "" { - continue - } - id, err := strconv.Atoi(part) - if err == nil { - result = append(result, id) - } - } - return result -} diff --git a/logger_test.go b/logger_test.go index 0590550..ec153a5 100644 --- a/logger_test.go +++ b/logger_test.go @@ -154,7 +154,7 @@ func TestClient_CustomLoggerUsedInRequest(t *testing.T) { // httptest server returns a valid JSON response for /team/list. ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") - fmt.Fprint(w, `{"data":{"items":[],"total":0}}`) + _, _ = fmt.Fprint(w, `{"data":{"items":[],"total":0}}`) })) defer ts.Close() diff --git a/monitors.go b/monitors.go index bd1ddf4..f8d8f19 100644 --- a/monitors.go +++ b/monitors.go @@ -24,11 +24,7 @@ type QueryMonitorRuleStatusOutput struct { } // QueryMonitorRuleStatus queries monitor rule status counts grouped by folder family. -func (c *Client) QueryMonitorRuleStatus(ctx context.Context, input *QueryMonitorRuleStatusInput) (*QueryMonitorRuleStatusOutput, error) { - if input == nil { - input = &QueryMonitorRuleStatusInput{} - } - +func (c *Client) QueryMonitorRuleStatus(ctx context.Context, _ *QueryMonitorRuleStatusInput) (*QueryMonitorRuleStatusOutput, error) { requestBody := map[string]any{} statuses, err := postData[[]MonitorRuleFolderStatus](c, ctx, "/monit/rule/counter/status", requestBody, "failed to query monitor rule status") diff --git a/templates.go b/templates.go index a1b4178..13654a4 100644 --- a/templates.go +++ b/templates.go @@ -168,9 +168,10 @@ func (c *Client) ValidateTemplate(ctx context.Context, input *ValidateTemplateIn if sizeLimit > 0 { if renderedSize > sizeLimit { sizeWarning := fmt.Sprintf("Rendered output is %d bytes, exceeding the %d byte limit for %s.", renderedSize, sizeLimit, input.Channel) - if input.Channel == "telegram" { + switch input.Channel { + case "telegram": sizeWarning += " CRITICAL: Telegram will silently drop this message." - } else if input.Channel == "teams_app" { + case "teams_app": sizeWarning += " Teams will return an error for this message." } errs = append(errs, sizeWarning) diff --git a/templates_test.go b/templates_test.go index da29c02..db19e6b 100644 --- a/templates_test.go +++ b/templates_test.go @@ -136,7 +136,7 @@ func TestGetPresetTemplate(t *testing.T) { if tt.serverResp != nil { ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(tt.serverResp) + _ = json.NewEncoder(w).Encode(tt.serverResp) })) defer ts.Close() } @@ -267,7 +267,7 @@ func TestValidateTemplate(t *testing.T) { if tt.serverResp != nil { ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(tt.serverResp) + _ = json.NewEncoder(w).Encode(tt.serverResp) })) defer ts.Close() }