install-shipbook — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited install-shipbook (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A full integration assistant for adding the Shipbook SDK to a project.
Scan the project to detect the platform:
Podfile or .xcodeproj → iOSbuild.gradle or build.gradle.kts → Androidpubspec.yaml → Flutterreact-native in package.json dependencies → React Nativepackage.json with browser/web framework (react, vue, angular, svelte) → Browserpackage.json with node/express/nestjs/fastify → Node.jsIf ambiguous, ask the user which platform.
iOS (Swift Package Manager): Add the package dependency https://github.com/ShipBook/ShipBookSDK-iOS.git via Xcode or Package.swift.
Android (Gradle): Add to build.gradle dependencies:
implementation 'io.shipbook:shipbooksdk:1.+'Flutter:
flutter pub add shipbook_flutterReact Native:
npm install @shipbook/react-nativeBrowser:
npm install @shipbook/browserNode.js:
npm install @shipbook/nodeCall get-account-apps to list the user's apps (returns name, appId, platform, key, integration).
create-app with a name to create oneappId and key to auto-populate the initialization codeAdd the import at the top of the file (with the other imports) and the start() call at the correct initialization point per platform:
iOS — import at top, start() in AppDelegate.application(_:didFinishLaunchingWithOptions:):
// top of file
import ShipBookSDK
// in didFinishLaunchingWithOptions
ShipBook.start(appId:"APP_ID", appKey:"APP_KEY")Android — import at top, start() in Application.onCreate():
// top of file
import io.shipbook.shipbooksdk.ShipBook;
// in onCreate()
ShipBook.start(this, "APP_ID", "APP_KEY");Flutter — import at top, start() in main():
// top of file
import 'package:shipbook_flutter/shipbook_flutter.dart';
// in main()
Shipbook.start('APP_ID', 'APP_KEY');React Native — import at top, start() at app initialization:
// top of file
import shipbook from '@shipbook/react-native';
// at app initialization
shipbook.start("APP_ID", "APP_KEY");Browser — import at top, start() early in app setup:
// top of file
import Shipbook from '@shipbook/browser';
// early in app setup
await Shipbook.start("APP_ID", "APP_KEY");Node.js — import at top, start() at startup before running server:
// top of file
import { Shipbook } from '@shipbook/node';
// at startup
await Shipbook.start("APP_ID", "APP_KEY");Scan the project for existing logging libraries:
Android — Timber: If timber is in dependencies, wrap it instead of replacing:
ShipBook.addWrapperClass(Timber::class.java.name)
Timber.plant(object : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
Log.message(tag, message, priority, t)
}
init {
ShipBook.addWrapperClass(this.javaClass.name)
}
})iOS — SwiftLog: If swift-log is in dependencies, use the Shipbook handler:
import LoggingShipbook
LoggingSystem.bootstrap(ShipbookLogHandler.init)Add https://github.com/ShipBook/swift-log-shipbook.git as a dependency.
Any platform (except Flutter) — Custom logger wrapper class: If the project has a custom logger wrapper class, register it so Shipbook captures the correct file/line info:
// Node.js / Browser / React Native
Shipbook.addWrapperClass(MyLogger);// Android
ShipBook.addWrapperClass(MyLogger::class.java.name)// iOS — create a wrapper function for each severity level (e, w, i, d, v),
// passing the caller's file/function/line so Shipbook shows the correct source location
func e(_ msg: String, tag: String? = nil, function: String = #function, file: String = #file, line: Int = #line) {
log.e(msg: msg, tag: tag, function: function, file: file, line: line)
}
func w(_ msg: String, tag: String? = nil, function: String = #function, file: String = #file, line: Int = #line) {
log.w(msg: msg, tag: tag, function: function, file: file, line: line)
}
func i(_ msg: String, tag: String? = nil, function: String = #function, file: String = #file, line: Int = #line) {
log.i(msg: msg, tag: tag, function: function, file: file, line: line)
}
// ... same pattern for d() and v()If no wrapper found: Replace raw log calls with Shipbook logger calls. Create logger instances per module: const log = Shipbook.getLogger("ModuleName")
For calls that already have a level (e.g., console.error, console.warn, Log.d(TAG, msg)), map to the corresponding Shipbook level.
For calls without a level (console.log, print(), NSLog()), do NOT blindly map them all to one level. Look at the context of each log statement and assign the correct level:
.v()): Development-only — should never be compiled into production. Temporary dev logs → .v() or remove entirely..d()): Lowest level acceptable in production but typically disabled. Server communication (excluding passwords), function entry/exit of important methods..i()): App progress and user navigation — app initialization, screen transitions, API calls (URL, status, response time only — not full payloads)..w()): Potentially harmful situations that aren't definitive errors. Use sparingly — e.g., repeated failed login attempts (3+ times), recurring network issues. Network connection failures (no internet, timeout) are not errors — a single failed attempt should be Debug at most; only escalate to Warning after repeated failures (3+ attempts)..e()): Recoverable error events where the app continues running — null pointer exceptions, server response parsing failures, server-returned errors. Not for network connectivity failures.Scan for Firebase Crashlytics in dependencies (firebase-crashlytics, FirebaseCrashlytics).
If found, modify the start() call to pass the session URL to Crashlytics:
Swift:
ShipBook.start("APP_ID", appKey:"APP_KEY") { (sessionUrl: String) -> () in
Crashlytics.crashlytics().setCustomValue(sessionUrl, forKey: "ShipbookSession")
}Kotlin:
ShipBook.start(this, "APP_ID", "APP_KEY") { sessionUrl ->
FirebaseCrashlytics.getInstance().setCustomKey("shipbookSession", sessionUrl)
}Java:
ShipBook.start(this, "APP_ID", "APP_KEY", (sessionUrl) -> {
FirebaseCrashlytics.getInstance().setCustomKey("shipbookSession", sessionUrl);
return Unit.INSTANCE;
});Ask the user: "Should I add logging to all API calls?"
If yes, detect the setup and add logging:
If framework middleware is available:
app.use(Shipbook.expressMiddleware())app.useGlobalInterceptors(Shipbook.nestjsInterceptor())If API calls are centralized (single API client/service class, e.g., an apiClient.ts, NetworkManager, ApiService): Add logging directly in that central place — log URL, method, status code, and duration at Info level.
If neither (scattered fetch/axios/HTTP calls):
fetch or axios with a logging interceptorLog format: log.i("API {METHOD} {URL} → {STATUS} ({DURATION}ms")
If the project has authentication (login flow, auth context, user session), add registerUser() after successful login and logout() on logout:
iOS (Swift):
ShipBook.registerUser(userId: "USER_ID", userName: "USER_NAME", fullName: "FULL_NAME", email: "EMAIL", phoneNumber: "PHONE", additionalInfo: ["key": "value"])
// on logout:
ShipBook.logout()Android (Kotlin):
ShipBook.registerUser(userId = "USER_ID", userName = "USER_NAME", fullName = "FULL_NAME", email = "EMAIL", phoneNumber = "PHONE", additionalInfo = mapOf("key" to "value"))
// on logout:
ShipBook.logout()Flutter (Dart):
Shipbook.registerUser(userId: 'USER_ID', userName: 'USER_NAME', fullName: 'FULL_NAME', email: 'EMAIL', phoneNumber: 'PHONE', additionalInfo: {'key': 'value'});
// on logout:
Shipbook.logout();React Native / Browser (JavaScript):
Shipbook.registerUser("USER_ID", "USER_NAME", "FULL_NAME", "EMAIL", "PHONE", { key: "value" });
// on logout:
Shipbook.logout();Node.js: User info is per-request via middleware context — registerUser() is not needed.
After completing the integration, run the audit-logs skill to scan for PII in logs, verify log level correctness, and check for sensitive data exposure.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.